Problem
When using z.union() for tool parameters, the schema fails validation:
[kernl] Invalid schema for function 'supermemory_documents_add': schema must be a JSON Schema of 'type: "object"', got 'type: "None"'.
Example
This pattern is useful for mutually exclusive parameters:
export const add = tool({
id: "supermemory_documents_add",
parameters: z.union([
z.object({
content: z.string().describe("Plaintext content"),
metadata: MetadataSchema,
}),
z.object({
url: z.url().describe("URL to ingest"),
metadata: MetadataSchema,
}),
]),
// ...
});
Current Workaround
Use a single object with optional fields and a .refine() for validation:
parameters: z
.object({
content: z.string().optional().describe("Plaintext (use this OR url)"),
url: z.string().url().optional().describe("URL (use this OR content)"),
metadata: MetadataSchema,
})
.refine((data) => Boolean(data.content) !== Boolean(data.url), {
message: "Provide either content or url, not both",
}),
Potential Solutions
- Transform unions to anyOf/oneOf - Some model providers support
oneOf in JSON Schema
- Flatten unions - If all union members are objects, merge their properties with optional markers
- Better error message - At minimum, surface a clearer error explaining the limitation
Context
Discovered while building the Supermemory toolkit where documents can be added via plaintext content OR URL, but not both.
Problem
When using
z.union()for tool parameters, the schema fails validation:Example
This pattern is useful for mutually exclusive parameters:
Current Workaround
Use a single object with optional fields and a
.refine()for validation:Potential Solutions
oneOfin JSON SchemaContext
Discovered while building the Supermemory toolkit where documents can be added via plaintext content OR URL, but not both.