# How to Distinguish Between Null and Missing Fields in Anthropic API Responses

> Learn how to distinguish null from missing fields in Anthropic API responses. Use model_fields_set and hasattr to correctly interpret your data and build robust applications.

- Repository: [Anthropic/anthropic-sdk-python](https://github.com/anthropics/anthropic-sdk-python)
- Tags: how-to-guide
- Published: 2026-02-23

---

**Use the `model_fields_set` property (or `__fields_set__` in Pydantic v1) to check if a field was present in the API response, and `hasattr()` or direct attribute access to detect explicit `null` values mapped to `None`.**

The Anthropic Python SDK materializes JSON API responses into **Pydantic `BaseModel`** subclasses, making it essential to distinguish between null and missing fields in API responses when handling optional parameters or partial updates. Understanding these semantics prevents bugs when the API explicitly returns `null` versus omitting a key entirely.

## How the Anthropic SDK Represents Null vs Missing Fields

When parsing API responses, the SDK maintains two distinct concepts:

| Concept | SDK Representation | Detection Method |
|---------|-------------------|------------------|
| **Field present with value `null`** | Attribute exists with value `None` | `hasattr(obj, "field")` returns `True` |
| **Field completely absent** | Attribute not in `__fields_set__`, access raises `AttributeError` | `"field" in obj.model_fields_set` returns `False` |

This distinction is critical for endpoints that treat explicit `null` as "clear this value" versus omitted fields as "no change."

## Tracking Missing Fields in Pydantic Models

### The `NotGiven` Sentinel for Requests

When constructing requests, the SDK uses a `NotGiven` sentinel defined in [`src/anthropic/_types.py`](https://github.com/anthropics/anthropic-sdk-python/blob/main/src/anthropic/_types.py) to distinguish between omitting a parameter and passing `None`:

```python

# src/anthropic/_types.py – NotGiven definition

# https://github.com/anthropics/anthropic-sdk-python/blob/main/src/anthropic/_types.py#L27-L57

class NotGiven:
    """Distinguishes between an explicit `None` and an omitted argument."""
    def __bool__(self) -> Literal[False]:
        return False
    def __repr__(self) -> str:
        return "NOT_GIVEN"

not_given = NotGiven()

```

Passing `NotGiven` (or simply omitting the parameter) causes the request builder to exclude the key entirely, while passing `None` sends an explicit `null` in the JSON payload.

### The `__fields_set__` and `model_fields_set` Properties

In [`src/anthropic/_models.py`](https://github.com/anthropics/anthropic-sdk-python/blob/main/src/anthropic/_models.py), the SDK provides a compatibility shim that exposes which fields were actually supplied by the API:

```python

# src/anthropic/_models.py – fields-set shim

# https://github.com/anthropics/anthropic-sdk-python/blob/main/src/anthropic/_models.py#L100-L105

@property
def model_fields_set(self) -> set[str]:
    # forwards-compat shim for pydantic v2

    return self.__fields_set__  # type: ignore

```

The `__fields_set__` attribute (Pydantic v1) or `model_fields_set` property (unified interface) contains a `set` of field names that were present in the source JSON. Fields not in this set were omitted by the API.

### Response Parsing and Field Construction

The transformation from raw HTTP response to model occurs in [`src/anthropic/_response.py`](https://github.com/anthropics/anthropic-sdk-python/blob/main/src/anthropic/_response.py):

```python

# src/anthropic/_response.py – JSON parsing path

# https://github.com/anthropics/anthropic-sdk-python/blob/main/src/anthropic/_response.py#L89-L95

data = response.json()
return self._client._process_response_data(
    data=data,
    cast_to=cast_to,
    response=response,
)

```

The SDK uses `BaseModel.construct()` (or equivalent internal methods) to instantiate models without running full validation. This method preserves the distinction between fields provided as `None` versus fields not provided at all, populating `__fields_set__` accordingly.

## Practical Techniques to Detect Null vs Missing

### Checking for Explicit Null Values

To determine if a field exists but contains `None`:

```python
if hasattr(message, "stop_reason"):
    # Field was present in JSON (value could be None or a string)

    reason = message.stop_reason  # May be None

    if reason is None:
        print("API explicitly returned null")
    else:
        print("API returned value:", reason)

```

### Inspecting the Field Set

To distinguish between omitted fields and explicit nulls, use `model_fields_set`:

```python
if "stop_reason" in message.model_fields_set:
    # Field was present – safe to access, even if value is None

    print("Stop reason present:", message.stop_reason)
else:
    # The API never returned this key

    print("Stop reason not provided by API")

```

### Complete Working Example

```python
from anthropic import Anthropic, NotGiven

client = Anthropic()

# ------------------------------------------------------------------

# 1️⃣ Distinguish omitted vs explicit None in a request

# ------------------------------------------------------------------

# Omit the timeout (use API default)

resp1 = client.messages.create(
    model="claude-3-5-sonnet-20240620",
    max_tokens=100,
    temperature=0.5,
    # timeout omitted → NotGiven sentinel

    timeout=NotGiven,
)

# Explicitly ask for *no* timeout (null in JSON)

resp2 = client.messages.create(
    model="claude-3-5-sonnet-20240620",
    max_tokens=100,
    temperature=0.5,
    timeout=None,          # will be sent as `"timeout": null`

)

# ------------------------------------------------------------------

# 2️⃣ Detect null vs missing in a response model

# ------------------------------------------------------------------

msg = resp1.content[0]          # Assume a Message object

if "stop_reason" in msg.model_fields_set:
    # `stop_reason` was present – could be None or a string

    print("Stop reason:", msg.stop_reason)
else:
    # The API never returned the key

    print("Stop reason not provided")

```

## Why Distinguishing Null from Missing Matters

**Business Logic Precision**: Some Anthropic API endpoints treat explicit `null` as "clear this value" while omitted fields mean "no change" or "use default." Misinterpreting these signals can lead to unintended state modifications.

**Backward Compatibility**: The `NotGiven` sentinel (defined in [`src/anthropic/_types.py`](https://github.com/anthropics/anthropic-sdk-python/blob/main/src/anthropic/_types.py)) allows client code to remain compatible with API changes. When new optional parameters are added, existing code that omits them (using `NotGiven`) continues to work without modification, whereas passing `None` might trigger new validation logic.

## Summary

- **Explicit `null`**: Appears as `None` on the model attribute and is included in `model_fields_set` (or `__fields_set__`).
- **Missing fields**: Absent from `model_fields_set`; accessing them raises `AttributeError` unless checked with `hasattr()`.
- **Request construction**: Use `NotGiven` (from [`src/anthropic/_types.py`](https://github.com/anthropics/anthropic-sdk-python/blob/main/src/anthropic/_types.py)) to omit parameters; use `None` to send explicit `null` values.
- **Detection pattern**: Check `"field" in obj.model_fields_set` to determine if the API returned the key, then check `obj.field is None` to detect explicit nulls.

## Frequently Asked Questions

### How do I check if a field was omitted in an Anthropic API response?

Use the `model_fields_set` property available on all SDK response models. If the field name is not in this set, the API did not include it in the JSON payload. For example: `if "stop_reason" not in message.model_fields_set: print("Field omitted")`.

### What is the difference between `None` and `NotGiven` in the Anthropic SDK?

`None` represents an explicit JSON `null` value that will be serialized and sent to the API, indicating the field should be cleared or set to null. `NotGiven` (from [`src/anthropic/_types.py`](https://github.com/anthropics/anthropic-sdk-python/blob/main/src/anthropic/_types.py)) is a sentinel class indicating the caller did not provide the argument, causing the SDK to omit the key entirely from the request body.

### Can I use `hasattr()` to detect missing fields in Pydantic models?

Yes, but with caution. `hasattr(obj, "field")` returns `True` if the attribute exists on the model, which includes fields explicitly set to `None`. However, for fields truly missing from the API response (not in `__fields_set__`), Pydantic models typically raise `AttributeError` on access, making `hasattr()` a valid detection mechanism alongside checking `model_fields_set`.

### How does the SDK handle explicit null values in request parameters?

When you pass `None` to a client method parameter, the SDK serializes this as JSON `null` in the request body. This is handled in the request building logic where values are processed before transmission. In contrast, passing `NotGiven` ensures the parameter is excluded from the serialized JSON entirely, allowing the API to apply its default behavior.