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

  1. Use the cycle handling option that emits $refs (e.g. zodToJsonSchema(schema, { cycle: 'ref' })) instead of 'none'/'seen'.
  2. Restructure the zod schema to break the recursion (depth cap, iterative shape) so conversion succeeds without cycles.
  3. Manually define the recursive part of the JSON Schema and merge it with the converted output.
  4. 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

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


AI-assisted analysis of vercel/ai@69428b1f8b (2026-08-30). Data as JSON: /api/errors/8edaf7873d9bacd4. Report an issue: GitHub.