Skip to content

[Go] InferJSONSchema produces invalid schema for repeated struct types #4119

@stephenafamo

Description

@stephenafamo

Describe the bug

When using ai.WithOutputType() with a dynamically created struct where multiple fields share the same Go type, InferJSONSchema produces an invalid JSON Schema that causes the Gemini plugin to fail.

Full error message:

schema is missing the 'type' field: map[string]interface {}{"additionalProperties":true}

The root cause is in internal/base/json.go. The inferSchema function tracks "seen" types to handle recursive references. When a struct type is encountered more than once, it returns:

if seen[t] {
    return &jsonschema.Schema{AdditionalProperties: jsonschema.TrueSchema}
}

This produces {"additionalProperties": true} which is missing the required type field. The Gemini plugin's toGeminiSchema function in plugins/googlegenai/gemini.go then rejects this schema.

To Reproduce

package main

import (
    "context"
    "reflect"
    
    "github.com/firebase/genkit/go/ai"
    "github.com/firebase/genkit/go/genkit"
    "github.com/firebase/genkit/go/plugins/googlegenai"
)

type Message struct {
    ID    string `json:"id"`
    Text  string `json:"text"`
}

func main() {
    ctx := context.Background()
    kit := genkit.Init(ctx, genkit.WithPlugins(&googlegenai.GoogleAI{}))
    model := googlegenai.GoogleAIModel(kit, "gemini-2.5-flash")

    // Create a dynamic struct with multiple fields of the same type
    messageTyp := reflect.TypeFor[Message]()
    fields := []reflect.StructField{
        {Name: "Key1", Type: messageTyp},
        {Name: "Key2", Type: messageTyp}, // Second occurrence triggers the bug
    }
    outputType := reflect.New(reflect.StructOf(fields)).Interface()

    // This will fail with: "schema is missing the 'type' field"
    _, err := genkit.Generate(
        ctx, kit,
        ai.WithModel(model),
        ai.WithOutputType(outputType),
        ai.WithPrompt("Return two messages"),
    )
    if err != nil {
        panic(err)
    }
}

Expected behavior

The schema for repeated types should include a type field. For example:

{"type": "object", "additionalProperties": true}

Suggested fix in internal/base/json.go:

if seen[t] {
    return &jsonschema.Schema{
        Type:                 "object",
        AdditionalProperties: jsonschema.TrueSchema,
    }
}

Screenshots

N/A

Runtime (please complete the following information):

  • OS: MacOS
  • Version: Sequoia 15.5
  • Genkit version: v1.3.0

Go version

go version go1.25.0 darwin/arm64

Additional context

Workaround: Use ai.WithOutputSchema() with a manually constructed schema instead of ai.WithOutputType():

messageSchema := map[string]any{
    "type": "object",
    "properties": map[string]any{
        "id":   map[string]any{"type": "string"},
        "text": map[string]any{"type": "string"},
    },
}

outputSchema := map[string]any{
    "type": "object",
    "properties": map[string]any{
        "Key1": messageSchema,
        "Key2": messageSchema,
    },
}

_, err := genkit.Generate(
    ctx, kit,
    ai.WithModel(model),
    ai.WithOutputSchema(outputSchema),
    ai.WithPrompt("Return two messages"),
)

Metadata

Metadata

Assignees

Labels

bugSomething isn't workinggo

Type

No type

Projects

Status

No status

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions