vercel/ai · warning
Recursive reference detected at ${refs.currentPath.join('/')
Error message
Recursive reference detected at ${refs.currentPath.join('/')}! Defaulting to any What it means
During zod v3 schema-to-JSON-Schema conversion, a recursive ($ref) definition is encountered a second time while already being resolved, i.e. the cycle cannot be represented at the current path, so the converter emits this warning and substitutes an "any" JSON schema for that node. The resulting JSON Schema is therefore less precise than the zod schema.
Source
Thrown at packages/provider-utils/src/to-json-schema/zod3-to-json-schema/parse-def.ts:86
refs: Refs,
):
| {
$ref: string;
}
| {}
| undefined => {
switch (refs.$refStrategy) {
case 'root':
return { $ref: item.path.join('/') };
case 'relative':
return { $ref: getRelativePath(refs.currentPath, item.path) };
case 'none':
case 'seen': {
if (
item.path.length < refs.currentPath.length &&
item.path.every((value, index) => refs.currentPath[index] === value)
) {
console.warn(
`Recursive reference detected at ${refs.currentPath.join(
'/',
)}! Defaulting to any`,
);
return parseAnyDef();
}
return refs.$refStrategy === 'seen' ? parseAnyDef() : undefined;
}
}
};
const addMeta = (
def: ZodTypeDef,
refs: Refs,
jsonSchema: JsonSchema7Type,
): JsonSchema7Type => {View on GitHub (pinned to 69428b1f8b)
Solutions
- Use the cycle handling option that emits $refs (e.g. zodToJsonSchema(schema, { cycle: 'ref' })) instead of 'none'/'seen'.
- Restructure the zod schema to break the recursion (depth cap, iterative shape) so conversion succeeds without cycles.
- Manually define the recursive part of the JSON Schema and merge it with the converted output.
- Treat the warning as acceptable if 'any' at that node is tolerable.
Example fix
// before
const jsonSchema = zod3ToJSONSchema(recursiveSchema); // warns, any at cycle
// after
const jsonSchema = zod3ToJSONSchema(recursiveSchema, { cycle: 'ref' }); Defensive patterns
Strategy: validation
Validate before calling
// detect recursion before converting
function isRecursive(zodSchema) { /* walk .def / .shape checking self references */ }
// or: opt into $ref cycle handling up front
zod3ToJSONSchema(schema, { cycle: 'ref' }); Prevention
- Prefer cycle: 'ref' when converting schemas that may be recursive
- Spot-check generated JSON Schema for 'any' nodes in tests
- Avoid lazy()/self-referencing zod types in schemas destined for strict JSON Schema consumers
When it happens
Trigger: Calling zodToJsonSchema (zod3toJSONSchema) on a zod schema containing recursive references (e.g. a self-referencing object or lazy() type) whose cycle resolution mode cannot emit a $ref at that position (path/refs settings).
Common situations: Converting tree-like zod schemas (comments, categories, nested menus) for structured output with generateObject or provider tool schemas; passing a 'seen' cycle handling mode where $ref is unsupported.
Related errors
- Could not convert regex pattern at ${refs.currentPath.join('
- Google schema conversion does not support recursive JSON Sch
- Google schema conversion only supports references to direct
- Google does not support this JSON Schema enum. Enum values m
- No object generated: response did not match schema.
AI-assisted analysis of vercel/ai@69428b1f8b (2026-08-30).
Data as JSON: /api/errors/8edaf7873d9bacd4.
Report an issue: GitHub.