Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/fix-openai-responses-pattern-keyword.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@ai-sdk/openai": patch
---

Fix `server_error` in OpenAI Responses API when schemas generated by zod v4 contain `pattern` keywords with unsupported regex features (e.g. lookaheads from `z.email()`, `z.uuid()`). The `pattern` keyword is now stripped from response format schemas and tool parameters before they are sent to the API.
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { removePatternKeyword } from './openai-responses-sanitize-schema';
import {
APICallError,
type JSONValue,
Expand Down Expand Up @@ -345,7 +346,7 @@ export class OpenAIResponsesLanguageModel implements LanguageModelV4 {
strict: strictJsonSchema,
name: responseFormat.name ?? 'response',
description: responseFormat.description,
schema: responseFormat.schema,
schema: removePatternKeyword(responseFormat.schema),
}
: { type: 'json_object' },
}),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import type {
OpenAIResponsesFunctionTool,
OpenAIResponsesTool,
} from './openai-responses-api';
import { removePatternKeyword } from './openai-responses-sanitize-schema';

type OpenAIToolOptions = {
deferLoading?: boolean;
Expand Down Expand Up @@ -404,7 +405,7 @@ function prepareFunctionTool({
type: 'function',
name: tool.name,
description: tool.description,
parameters: tool.inputSchema,
parameters: removePatternKeyword(tool.inputSchema),
...(tool.strict != null ? { strict: tool.strict } : {}),
...(deferLoading != null ? { defer_loading: deferLoading } : {}),
};
Expand Down
52 changes: 52 additions & 0 deletions packages/openai/src/responses/openai-responses-sanitize-schema.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
// OpenAI structured outputs rejects JSON Schema `pattern` values that contain
// regex features it does not support (e.g. lookaheads). zod v4's toJSONSchema()
// emits `pattern` for string validators like z.email(), z.uuid(), z.iso.date().
// Strip the keyword recursively before sending schemas to the Responses API.
//
// Only standard JSON Schema structural keys are recursed into, so that tool or
// response parameters whose name happens to be "pattern" are never touched.
export function removePatternKeyword<T>(schema: T): T {
if (!schema || typeof schema !== 'object') return schema;
if (Array.isArray(schema)) return schema.map(removePatternKeyword) as unknown as T;

const result = { ...(schema as Record<string, unknown>) };

// Remove the JSON Schema string-validator keyword at this level.
delete result['pattern'];

Comment thread
vercel[bot] marked this conversation as resolved.
// Keys whose values are { name → schema } maps. Recurse into the schema
// values but preserve the keys — a key named "pattern" here is a user-
// defined property name, not the JSON Schema keyword.
for (const mapKey of ['properties', 'patternProperties', '$defs', 'definitions']) {
if (
result[mapKey] &&
typeof result[mapKey] === 'object' &&
!Array.isArray(result[mapKey])
) {
result[mapKey] = Object.fromEntries(
Object.entries(result[mapKey] as Record<string, unknown>).map(
([k, v]) => [k, removePatternKeyword(v)],
),
);
}
}

// Keys whose values are sub-schemas or arrays of sub-schemas.
for (const schemaKey of [
'items',
'allOf',
'anyOf',
'oneOf',
'not',
'additionalProperties',
'if',
'then',
'else',
]) {
if (result[schemaKey] !== undefined) {
result[schemaKey] = removePatternKeyword(result[schemaKey]);
}
}

return result as unknown as T;
}