You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Resume import fails with Anthropic: “compiled grammar is too large” #24
Provider: Anthropic, tested with claude-sonnet-5-5 and claude-haiku-4-5
What happens: Importing a resume in Profile fails with “Something went wrong while working on this.” The log shows AiError: The AI provider ran into a problem. Test connection works.
Also: RangeError: Invalid time zone specified: Etc/Unknown appears in the logs while TZ is unset; setting TZ fixes it.
What did you expect to happen?
Cause: The extracted_profile schema from extract-profile.ts (via zodOutputFormat) is rejected by the Messages API. Sending that schema directly in output_config.format, with a three-line resume, returns:
400 invalid_request_error: The compiled grammar is too large, which would cause performance issues. Simplify your tool schemas or reduce the number of strict tools.
(request_id: req_011CgUiKPa2umKFjM8jGbmpb)
How can we make it happen?
The schema has about 32 nullable fields. Anthropic’s structured outputs docs list a limit of 16 parameters with union types, and say larger schemas can fail to compile.
Possible fix: On this 400, retry without output_config.format, with the schema described in the prompt; the answer is already validated with zod. Or simplify the schema, for example by using empty strings instead of null.
Same issue here: Dossier 1.9.2 built from source with Node.js, Anthropic claude-sonnet-5. Profile import from a PDF failed with "The AI provider ran into a problem", and Test connection worked. No failed request showed up in the Console's Logs.
I tried the first fix suggested above. If the request with output_config.format gets a 400, it retries once without the format and puts the schema in the system prompt with withJsonSchema. The answer still goes through the same zod validation. Import worked on the first try after that. The AI tests pass: yarn vitest run src/lib/ai, 154 passed.
Patch to src/lib/ai/providers/anthropic.ts:
diff --git a/src/lib/ai/providers/anthropic.ts b/src/lib/ai/providers/anthropic.ts
index 8e45d13..105648b 100644
--- a/src/lib/ai/providers/anthropic.ts+++ b/src/lib/ai/providers/anthropic.ts@@ -4,7 +4,7 @@ import Anthropic from "@anthropic-ai/sdk";
import { zodOutputFormat } from "@anthropic-ai/sdk/helpers/zod";
import { AiError } from "../errors";
-import { BaseProvider, type ChatAnswer, type ChatCall, type Effort } from "../provider";+import { BaseProvider, type ChatAnswer, type ChatCall, type Effort, withJsonSchema } from "../provider";
import { keyGuardedFetch } from "./guarded-fetch";
/** Offered when the model list can't be fetched, e.g. before a key is saved. */
@@ -44,17 +44,29 @@ export class AnthropicProvider extends BaseProvider {
protected async chat(call: ChatCall): Promise<ChatAnswer> {
if (!this.client) throw AiError.config("Add your Anthropic API key in Settings → AI provider first.");
const effort = call.effort && (await this.effortLevels(this.client, call.model, call.signal)).has(call.effort) ? call.effort : undefined;
- const outputConfig = { ...(call.json ? { format: zodOutputFormat(call.json.schema) } : {}), ...(effort ? { effort } : {}) };- const message = await this.client.messages.create(- {- model: call.model,- max_tokens: call.maxTokens + THINKING_TOKENS,- system: call.system,- messages: call.messages,- ...(Object.keys(outputConfig).length > 0 ? { output_config: outputConfig } : {}),- },- { signal: call.signal },- );+ const send = (structured: boolean) => {+ const outputConfig = { ...(structured && call.json ? { format: zodOutputFormat(call.json.schema) } : {}), ...(effort ? { effort } : {}) };+ return this.client!.messages.create(+ {+ model: call.model,+ max_tokens: call.maxTokens + THINKING_TOKENS,+ system: !structured && call.json ? withJsonSchema(call.system, call.json.schema) : call.system,+ messages: call.messages,+ ...(Object.keys(outputConfig).length > 0 ? { output_config: outputConfig } : {}),+ },+ { signal: call.signal },+ );+ };+ let message: Anthropic.Message;+ try {+ message = await send(true);+ } catch (error) {+ // Structured outputs refuse schemas with many nullable fields (the+ // profile import has 32) with a 400; the schema then goes in the prompt+ // instead, and the answer is still validated against it.+ if (!call.json || !(error instanceof Anthropic.BadRequestError)) throw error;+ message = await send(false);+ }
if (message.stop_reason === "refusal") {
throw new AiError("provider", "The model declined to answer this one. Try rewording it, or try again.", "refusal");
}
It retries on any BadRequestError when a schema was sent. You might prefer to match only the "compiled grammar is too large" message, so other 400s fail fast.
Etc/Unknown:TZ now defaults to UTC, and Dossier uses UTC whenever the server's time zone isn't one it knows. If you use compose.production.yml, take the new one.
@Jchinonso, your #30 does the same as #16, so I'm closing it in favour of the release. Thanks for testing it by hand.
Activity
Jchinonso commentedon Oct 29, 2026
Same issue here: Dossier 1.9.2 built from source with Node.js, Anthropic
claude-sonnet-5. Profile import from a PDF failed with "The AI provider ran into a problem", and Test connection worked. No failed request showed up in the Console's Logs.I tried the first fix suggested above. If the request with
output_config.formatgets a 400, it retries once without the format and puts the schema in the system prompt withwithJsonSchema. The answer still goes through the same zod validation. Import worked on the first try after that. The AI tests pass:yarn vitest run src/lib/ai, 154 passed.Patch to
src/lib/ai/providers/anthropic.ts:It retries on any
BadRequestErrorwhen a schema was sent. You might prefer to match only the "compiled grammar is too large" message, so other 400s fail fast.Dossier 1.10.0
AienTech commentedon Oct 29, 2026
Thanks both! Both parts are fixed in 1.10.0:
Etc/Unknown:TZnow defaults to UTC, and Dossier uses UTC whenever the server's time zone isn't one it knows. If you usecompose.production.yml, take the new one.@Jchinonso, your #30 does the same as #16, so I'm closing it in favour of the release. Thanks for testing it by hand.