> ## Documentation Index
> Fetch the complete documentation index at: https://docs.instructorphp.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Debugging

## Overview

When a request does not behave as expected, Instructor provides several inspection
points at different levels of detail. Start with the smallest useful tool and
escalate as needed.

## Quick Inspection Points

### Response Envelope

The `response()` method returns a `StructuredOutputResponse` that pairs the parsed
value with the raw provider response:

```php theme={null}
$response = (new StructuredOutput())
    ->with(messages: '...', responseModel: User::class)
    ->response();

// The deserialized value
dump($response->value());

// The raw inference response from the provider
dump($response->inferenceResponse());

// Token usage statistics
dump($response->usage());

// Why the model stopped generating
dump($response->finishReason());
// @doctest id="0645"
```

### Raw Provider Response

If you only need the raw inference response without deserialization metadata:

```php theme={null}
$raw = (new StructuredOutput())
    ->with(messages: '...', responseModel: User::class)
    ->inferenceResponse();

dump($raw->content());
dump($raw->toolCalls());
// @doctest id="11c1"
```

### Execution Metadata

Access the execution object from a `PendingStructuredOutput` to inspect the request
configuration, attempt history, and output mode:

```php theme={null}
$pending = (new StructuredOutput())
    ->with(messages: '...', responseModel: User::class)
    ->create();

$execution = $pending->execution();
dump($execution->outputMode());
dump($execution->request());
// @doctest id="8f7c"
```

### Streaming Responses

When streaming, use `responses()` to inspect each emitted `StructuredOutputResponse`:

```php theme={null}
$stream = (new StructuredOutput())
    ->with(messages: '...', responseModel: User::class)
    ->stream();

foreach ($stream->responses() as $response) {
    echo $response->isPartial() ? 'partial' : 'final';
    dump($response->value());
}
// @doctest id="5a70"
```

## Runtime Events

For deeper tracing, attach a wiretap to the runtime. This gives you visibility
into every internal stage -- schema building, inference calls, extraction,
deserialization, validation, and transformation:

```php theme={null}
$runtime = StructuredOutputRuntime::fromDefaults()
    ->wiretap(fn($event) => $event->print());

$result = (new StructuredOutput($runtime))
    ->with(messages: '...', responseModel: User::class)
    ->get();
// @doctest id="8b43"
```

For targeted debugging, listen to specific event types:

```php theme={null}
use Cognesy\Instructor\Events\Response\ResponseValidationFailed;
use Cognesy\Instructor\Events\Response\ResponseDeserializationFailed;
use Cognesy\Instructor\Events\Request\NewValidationRecoveryAttempt;

$runtime = StructuredOutputRuntime::fromDefaults()
    ->onEvent(ResponseValidationFailed::class, fn($e) => dump('Validation failed:', $e->data))
    ->onEvent(ResponseDeserializationFailed::class, fn($e) => dump('Deserialization failed:', $e->data))
    ->onEvent(NewValidationRecoveryAttempt::class, fn($e) => dump('Retrying...', $e->data));
// @doctest id="5518"
```

See the [Events](events) page for the full list of available event classes.

## JSON Output Inspection

When you need to see the raw JSON that came back from the provider (before
deserialization), use the `toJson()` or `toArray()` methods on `PendingStructuredOutput`:

```php theme={null}
$pending = (new StructuredOutput())
    ->with(messages: '...', responseModel: User::class)
    ->create();

// Raw JSON string
echo $pending->toJson();

// Parsed array
dump($pending->toArray());
// @doctest id="1137"
```

## Common Debugging Scenarios

### Wrong or Missing Fields

Check that your response model class has the correct property types and names.
Use `wiretap()` to inspect the raw JSON from the provider and compare it with your
schema expectations.

### Validation Failures Exhausting Retries

Listen for `ResponseValidationFailed` events to see exactly which validation rules
are failing. Consider increasing `maxRetries` or relaxing validation constraints.

### Unexpected Deserialization Errors

Listen for `ResponseDeserializationFailed` to see the raw data that could not be
mapped to your class. This often reveals type mismatches between the schema and
the actual model response.

### Streaming Not Producing Updates

Verify that `withStreaming(true)` is set and that you are consuming the stream
(e.g., iterating `partials()` or calling `finalValue()`). The stream is lazy --
no data flows until you start reading.
