Schema mismatch when using `@effect/ai-anthropic` with the Anthropic API
What version of Effect is running?
3.16.8
What steps can reproduce the bug?
Replace @effect/ai-openai with @effect/ai-anthropic in the example in the docs.
Repro: https://github.com/giacomoran/effect-anthropic-api
What is the expected behavior?
The program should run without schema mismatch errors.
What do you see instead?
I get the following ParseError in AnthropicLanguageModel.generateText while decoding the response body:
AiError: AnthropicLanguageModel.generateText: An error occurred
at cause (/Users/giacomoran/Projects/zxtra/effect-anthropic-api/node_modules/.pnpm/@[email protected]_@[email protected]_@[email protected]_@[email protected]_zjppir72d2pyzzcr5qk2drd4ne/node_modules/@effect/ai-anthropic/src/AnthropicLanguageModel.ts:187:37)
at cause (/Users/giacomoran/Projects/zxtra/effect-anthropic-api/node_modules/.pnpm/[email protected]/node_modules/effect/src/internal/core.ts:910:24)
at <anonymous> (/Users/giacomoran/Projects/zxtra/effect-anthropic-api/node_modules/.pnpm/[email protected]/node_modules/effect/src/internal/fiberRuntime.ts:1186:44)
at body (/Users/giacomoran/Projects/zxtra/effect-anthropic-api/node_modules/.pnpm/[email protected]/node_modules/effect/src/Utils.ts:786:14)
at FiberRuntime.Failure (/Users/giacomoran/Projects/zxtra/effect-anthropic-api/node_modules/.pnpm/[email protected]/node_modules/effect/src/internal/fiberRuntime.ts:1186:20)
at <anonymous> (/Users/giacomoran/Projects/zxtra/effect-anthropic-api/node_modules/.pnpm/[email protected]/node_modules/effect/src/internal/fiberRuntime.ts:1380:53)
at f (/Users/giacomoran/Projects/zxtra/effect-anthropic-api/node_modules/.pnpm/[email protected]/node_modules/effect/src/internal/tracer.ts:101:19)
at runLoop (/Users/giacomoran/Projects/zxtra/effect-anthropic-api/node_modules/.pnpm/[email protected]/node_modules/effect/src/internal/fiberRuntime.ts:1370:34)
at evaluateEffect (/Users/giacomoran/Projects/zxtra/effect-anthropic-api/node_modules/.pnpm/[email protected]/node_modules/effect/src/internal/fiberRuntime.ts:936:27)
at evaluateMessageWhileSuspended (/Users/giacomoran/Projects/zxtra/effect-anthropic-api/node_modules/.pnpm/[email protected]/node_modules/effect/src/internal/fiberRuntime.ts:904:14)
at AiLanguageModel.generateText {
name: '(FiberFailure) AiError',
[Symbol(effect/Runtime/FiberFailure)]: Symbol(effect/Runtime/FiberFailure),
[Symbol(effect/Runtime/FiberFailure/Cause)]: {
_tag: 'Fail',
error: AiError: AnthropicLanguageModel.generateText: An error occurred
at cause (/Users/giacomoran/Projects/zxtra/effect-anthropic-api/node_modules/.pnpm/@[email protected]_@[email protected]_@[email protected]_@[email protected]_zjppir72d2pyzzcr5qk2drd4ne/node_modules/@effect/ai-anthropic/src/AnthropicLanguageModel.ts:187:37)
at cause (/Users/giacomoran/Projects/zxtra/effect-anthropic-api/node_modules/.pnpm/[email protected]/node_modules/effect/src/internal/core.ts:910:24)
at <anonymous> (/Users/giacomoran/Projects/zxtra/effect-anthropic-api/node_modules/.pnpm/[email protected]/node_modules/effect/src/internal/fiberRuntime.ts:1186:44)
at body (/Users/giacomoran/Projects/zxtra/effect-anthropic-api/node_modules/.pnpm/[email protected]/node_modules/effect/src/Utils.ts:786:14)
at FiberRuntime.Failure (/Users/giacomoran/Projects/zxtra/effect-anthropic-api/node_modules/.pnpm/[email protected]/node_modules/effect/src/internal/fiberRuntime.ts:1186:20)
at <anonymous> (/Users/giacomoran/Projects/zxtra/effect-anthropic-api/node_modules/.pnpm/[email protected]/node_modules/effect/src/internal/fiberRuntime.ts:1380:53)
at f (/Users/giacomoran/Projects/zxtra/effect-anthropic-api/node_modules/.pnpm/[email protected]/node_modules/effect/src/internal/tracer.ts:101:19)
at runLoop (/Users/giacomoran/Projects/zxtra/effect-anthropic-api/node_modules/.pnpm/[email protected]/node_modules/effect/src/internal/fiberRuntime.ts:1370:34)
at evaluateEffect (/Users/giacomoran/Projects/zxtra/effect-anthropic-api/node_modules/.pnpm/[email protected]/node_modules/effect/src/internal/fiberRuntime.ts:936:27)
at evaluateMessageWhileSuspended (/Users/giacomoran/Projects/zxtra/effect-anthropic-api/node_modules/.pnpm/[email protected]/node_modules/effect/src/internal/fiberRuntime.ts:904:14) {
module: 'AnthropicLanguageModel',
method: 'generateText',
description: 'An error occurred',
_tag: 'AiError',
[Symbol(@effect/ai/AiError)]: Symbol(@effect/ai/AiError),
[cause]: ParseError: (Message (Encoded side) <-> Message)
└─ Encoded side transformation failure
└─ Message (Encoded side)
└─ ["content"]
└─ ReadonlyArray<{ readonly citations: ReadonlyArray<{ readonly cited_text: string; readonly document_index: Int & greaterThanOrEqualTo(0); readonly document_title: string | null; readonly end_char_index: Int; readonly start_char_index: Int & greaterThanOrEqualTo(0); readonly type: "char_location" } | { readonly cited_text: string; readonly document_index: Int & greaterThanOrEqualTo(0); readonly document_title: string | null; readonly end_page_number: Int; readonly start_page_number: Int & greaterThanOrEqualTo(1); readonly type: "page_location" } | { readonly cited_text: string; readonly document_index: Int & greaterThanOrEqualTo(0); readonly document_title: string | null; readonly end_block_index: Int; readonly start_block_index: Int & greaterThanOrEqualTo(0); readonly type: "content_block_location" } | { readonly cited_text: string; readonly encrypted_index: string; readonly title: string | null; readonly type: "web_search_result_location"; readonly url: string }> | null | null; readonly text: minLength(0) & maxLength(5000000); readonly type: "text" } | { readonly id: a string matching the pattern ^[a-zA-Z0-9_-]+$; readonly input: { readonly [x: string]: unknown }; readonly name: minLength(1); readonly type: "tool_use" } | { readonly id: a string matching the pattern ^srvtoolu_[a-zA-Z0-9_]+$; readonly input: { readonly [x: string]: unknown }; readonly name: "web_search"; readonly type: "server_tool_use" } | { readonly content: { readonly error_code: "invalid_tool_input" | "unavailable" | "max_uses_exceeded" | "too_many_requests" | "query_too_long"; readonly type: "web_search_tool_result_error" } | ReadonlyArray<{ readonly encrypted_content: string; readonly page_age: string | null | null; readonly title: string; readonly type: "web_search_result"; readonly url: string }>; readonly tool_use_id: a string matching the pattern ^srvtoolu_[a-zA-Z0-9_]+$; readonly type: "web_search_tool_result" } | { readonly signature: string; readonly thinking: string; readonly type: "thinking" } | { readonly data: string; readonly type: "redacted_thinking" }>
└─ [0]
└─ { readonly citations: ReadonlyArray<{ readonly cited_text: string; readonly document_index: Int & greaterThanOrEqualTo(0); readonly document_title: string | null; readonly end_char_index: Int; readonly start_char_index: Int & greaterThanOrEqualTo(0); readonly type: "char_location" } | { readonly cited_text: string; readonly document_index: Int & greaterThanOrEqualTo(0); readonly document_title: string | null; readonly end_page_number: Int; readonly start_page_number: Int & greaterThanOrEqualTo(1); readonly type: "page_location" } | { readonly cited_text: string; readonly document_index: Int & greaterThanOrEqualTo(0); readonly document_title: string | null; readonly end_block_index: Int; readonly start_block_index: Int & greaterThanOrEqualTo(0); readonly type: "content_block_location" } | { readonly cited_text: string; readonly encrypted_index: string; readonly title: string | null; readonly type: "web_search_result_location"; readonly url: string }> | null | null; readonly text: minLength(0) & maxLength(5000000); readonly type: "text" } | { readonly id: a string matching the pattern ^[a-zA-Z0-9_-]+$; readonly input: { readonly [x: string]: unknown }; readonly name: minLength(1); readonly type: "tool_use" } | { readonly id: a string matching the pattern ^srvtoolu_[a-zA-Z0-9_]+$; readonly input: { readonly [x: string]: unknown }; readonly name: "web_search"; readonly type: "server_tool_use" } | { readonly content: { readonly error_code: "invalid_tool_input" | "unavailable" | "max_uses_exceeded" | "too_many_requests" | "query_too_long"; readonly type: "web_search_tool_result_error" } | ReadonlyArray<{ readonly encrypted_content: string; readonly page_age: string | null | null; readonly title: string; readonly type: "web_search_result"; readonly url: string }>; readonly tool_use_id: a string matching the pattern ^srvtoolu_[a-zA-Z0-9_]+$; readonly type: "web_search_tool_result" } | { readonly signature: string; readonly thinking: string; readonly type: "thinking" } | { readonly data: string; readonly type: "redacted_thinking" }
├─ { readonly id: a string matching the pattern ^srvtoolu_[a-zA-Z0-9_]+$; readonly input: { readonly [x: string]: unknown }; readonly name: "web_search"; readonly type: "server_tool_use" }
│ └─ ["name"]
│ └─ is missing
└─ { readonly citations: ReadonlyArray<{ readonly cited_text: string; readonly document_index: Int & greaterThanOrEqualTo(0); readonly document_title: string | null; readonly end_char_index: Int; readonly start_char_index: Int & greaterThanOrEqualTo(0); readonly type: "char_location" } | { readonly cited_text: string; readonly document_index: Int & greaterThanOrEqualTo(0); readonly document_title: string | null; readonly end_page_number: Int; readonly start_page_number: Int & greaterThanOrEqualTo(1); readonly type: "page_location" } | { readonly cited_text: string; readonly document_index: Int & greaterThanOrEqualTo(0); readonly document_title: string | null; readonly end_block_index: Int; readonly start_block_index: Int & greaterThanOrEqualTo(0); readonly type: "content_block_location" } | { readonly cited_text: string; readonly encrypted_index: string; readonly title: string | null; readonly type: "web_search_result_location"; readonly url: string }> | null | null; readonly text: minLength(0) & maxLength(5000000); readonly type: "text" }
└─ ["citations"]
└─ is missing
at issue (/Users/giacomoran/Projects/zxtra/effect-anthropic-api/node_modules/.pnpm/[email protected]/node_modules/effect/src/ParseResult.ts:266:62)
at <anonymous> (/Users/giacomoran/Projects/zxtra/effect-anthropic-api/node_modules/.pnpm/[email protected]/node_modules/effect/src/Either.ts:439:25)
at Module.<anonymous> (/Users/giacomoran/Projects/zxtra/effect-anthropic-api/node_modules/.pnpm/[email protected]/node_modules/effect/src/Function.ts:245:18)
at <anonymous> (/Users/giacomoran/Projects/zxtra/effect-anthropic-api/node_modules/.pnpm/[email protected]/node_modules/effect/src/ParseResult.ts:374:12)
at Module.<anonymous> (/Users/giacomoran/Projects/zxtra/effect-anthropic-api/node_modules/.pnpm/[email protected]/node_modules/effect/src/Function.ts:245:18)
at EffectPrimitive.effect_instruction_i1 (/Users/giacomoran/Projects/zxtra/effect-anthropic-api/node_modules/.pnpm/[email protected]/node_modules/effect/src/Schema.ts:565:17)
at <anonymous> (/Users/giacomoran/Projects/zxtra/effect-anthropic-api/node_modules/.pnpm/[email protected]/node_modules/effect/src/internal/fiberRuntime.ts:152:36)
at body (/Users/giacomoran/Projects/zxtra/effect-anthropic-api/node_modules/.pnpm/[email protected]/node_modules/effect/src/Utils.ts:786:14)
at Object.OnSuccess (/Users/giacomoran/Projects/zxtra/effect-anthropic-api/node_modules/.pnpm/[email protected]/node_modules/effect/src/internal/fiberRuntime.ts:152:12)
at FiberRuntime.Success (/Users/giacomoran/Projects/zxtra/effect-anthropic-api/node_modules/.pnpm/[email protected]/node_modules/effect/src/internal/fiberRuntime.ts:1171:37) {
issue: Transformation {
ast: Transformation {
from: [TypeLiteral],
to: [Declaration],
transformation: [FinalTransformation],
annotations: [Object],
_tag: 'Transformation'
},
actual: {
id: 'msg_019SNDEwNcJPqmTop1nS8y99',
type: 'message',
role: 'assistant',
model: 'claude-sonnet-4-20250514',
content: [Array],
stop_reason: 'end_turn',
stop_sequence: null,
usage: [Object]
},
kind: 'Encoded',
issue: Composite {
ast: [TypeLiteral],
actual: [Object],
issues: [Pointer],
output: [Object],
_tag: 'Composite'
},
_tag: 'Transformation'
},
_tag: 'ParseError',
[Symbol(effect/Schema/ParseErrorTypeId)]: Symbol(effect/Schema/ParseErrorTypeId)
}
}
}
}
Additional information
In the OpenAPI spec, used to generate Generated.ts in the @effect/ai-anthropic package, the citations property is marked as required but nullable in ResponseTextBlock.
The schema generated for ResponseTextBlock is:
export class ResponseTextBlock extends S.Struct({
"citations": S.NullOr(
S.Union(
S.Array(
S.Union(
ResponseCharLocationCitation,
ResponsePageLocationCitation,
ResponseContentBlockLocationCitation,
ResponseWebSearchResultLocationCitation
)
),
S.Null
)
),
"text": S.String.pipe(S.minLength(0), S.maxLength(5000000)),
"type": ResponseTextBlockType
}) {}
but the Anthropic API does not include the citations property in the response.
The received response body is:
{
id: 'msg_019SNDEwNcJPqmTop1nS8y99',
type: 'message',
role: 'assistant',
model: 'claude-sonnet-4-20250514',
content: [
{
type: 'text',
text: "Why don't scientists trust atoms?\n\nBecause they make up everything!"
}
],
stop_reason: 'end_turn',
stop_sequence: null,
usage: {
input_tokens: 11,
cache_creation_input_tokens: 0,
cache_read_input_tokens: 0,
output_tokens: 17,
service_tier: 'standard'
}
}
A similar issue for a different property if you replace AiLanguageModel.generateText with AiLanguageModel.generateObject in the repro. It seems like the OpenAPI spec published by Anthropic is not reliable. Other people have reported similar problems in the past: https://github.com/anthropics/anthropic-sdk-typescript/issues/605