Skip to content

OpenAI doesn't support z.record() in tool parameters #23

Description

@dremnik

Problem

When using z.record() in tool parameters, the schema serializes correctly to JSON Schema with additionalProperties, but OpenAI's function calling silently drops the field. The model never sees the parameter.

Works with: Anthropic (Claude)
Broken with: OpenAI (GPT)

Example

const createGist = tool({
  id: "github_gists_create",
  parameters: z.object({
    description: z.string().optional(),
    files: z.record(z.string(), z.object({ content: z.string() })), // <-- dropped by OpenAI
    public: z.boolean().optional(),
  }),
  // ...
});

Serializes to:

{
  "files": {
    "type": "object",
    "propertyNames": { "type": "string" },
    "additionalProperties": {
      "type": "object",
      "properties": { "content": { "type": "string" } },
      "required": ["content"]
    }
  }
}

OpenAI only shows description and public to the model - files is missing entirely.

Possible Solutions

  1. Document limitation - note that z.record() only works with Anthropic
  2. Use arrays instead - z.array(z.object({ key, value })) works everywhere
  3. Schema normalization layer - auto-convert records to arrays for OpenAI provider
  4. Warn at runtime - detect additionalProperties + OpenAI and log a warning

Workaround

Use array format for cross-provider compatibility:

files: z.array(z.object({
  filename: z.string(),
  content: z.string(),
}))

Then convert to record in the execute function.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions