anthropics / anthropics/anthropic-sdk-python

transform_schema raises AssertionError on valid list-form types, e.g. {"type": ["string", "null"]}

Đang mở
#1,764 2 bình luận 2 reaction 0 người được giao Xem trên GitHub
Ngôn ngữ chính
Python
Star
3.9k
Fork
853
Merge trung bình
1 ngày 18 giờ
Pull request đã merge (30 ngày)
11

Mô tả

### Summary

`transform_schema` (the structured-output schema transformer used by `messages.parse` / `beta.messages.parse`) crashes with an `AssertionError` on any schema that uses the list form of `type` — e.g. `{"type": ["string", "null"]}` — which is valid JSON Schema and explicitly supported by the Anthropic structured-outputs API.

The failure happens at request-build time, before any API call.

### Repro

```python
from anthropic import transform_schema

# Valid JSON Schema; also documented as supported by the structured-outputs API
transform_schema({"type": ["string", "null"]})
```

One-liner:

```bash
python -c 'from anthropic import transform_schema; transform_schema({"type": ["string", "null"]})'
```

Actual (on `anthropic==0.112.0`; the relevant code is unchanged on current `main` of `src/anthropic/lib/_parse/_transform.py`):

```
AssertionError: Expected code to be unreachable, but got: ['string', 'null']
```

A more realistic nested variant fails the same way:

```python
transform_schema({
"type": "object",
"properties": {"name": {"type": ["string", "null"]}},
"required": ["name"],
"additionalProperties": False,
})
```

### Expected

An equivalent transformed schema, e.g. rewriting the type union into `anyOf` branches:

```json
{"anyOf": [{"type": "string"}, {"type": "null"}]}
```

### Why this should be supported

- JSON Schema allows `type` to be "a string or an array of strings" — the list form is standard, not an extension.
- The [structured outputs docs](https://docs.claude.com/en/docs/build-with-claude/structured-outputs) explicitly document type arrays as supported (and meter them): *"Total parameters that use `anyOf` or type arrays (for example, `"type": ["string", "null"]`) across all strict schemas."* So the API accepts this shape; only the SDK-side transformer rejects it.
- Nullable-type unions are pervasive in real schemas: Pydantic `Optional[...]` fields in older/alternative generators, OpenAPI 3.1 output, GraphQL-derived schemas, and MCP tool `inputSchema`s commonly emit `"type": [..., "null"]`.

### Root cause

In `src/anthropic/lib/_parse/_transform.py`, `type_` is typed and handled as a scalar:

```python
type_: Optional[SupportedTypes] = json_schema.pop("type", None)
...
elif type_ == "boolean" or type_ == "integer" or type_ == "number" or type_ == "null" or type_ is None:
pass
else:
assert_never(type_)
```

A list value matches none of the scalar branches and falls into `assert_never`.

### Suggested fix

When `type_` is a list, canonicalize it before the scalar handling, e.g. rewrite `{"type": [t1, t2, ...], **rest}` into an `anyOf` of single-type branches (with sibling constraints attached to the non-`null` branches) and recurse. Single-element lists can collapse to the scalar form.

### Related (not duplicates)

- #1691 handles empty/typeless `{}` sub-schemas (`ValueError` path) — a different gap in the same function.
- #1185 discusses grammar-size limits and mentions type arrays as API-supported; it does not cover this SDK-side crash.

### Environment

- `anthropic==0.112.0` (also reproduces against `main`'s `_transform.py`)
- Python 3.12.13, macOS arm64

Hướng dẫn đóng góp

Mở hướng dẫn đóng góp

Đánh giá

Issue này chưa được đánh giá.

Nhận issue mới trong hộp thư của bạn

Bản tóm tắt ngắn những issue GitHub phù hợp với người mới.