Skip to content

bug(memory): graph extraction 400 Bad Request with OpenAI -- strict mode schema incompatibility #1656

@bug-ops

Description

@bug-ops

Bug

Graph entity extraction fails with 400 Bad Request when using OpenAI providers (gpt-4o-mini, gpt-4o).

Root Cause

GraphExtractor::extract() calls chat_typed_erased::<ExtractionResult> which uses cached_schema::<T>() to generate a JSON Schema via schemars::schema_for!(). The generated schema is sent as response_format: {type: "json_schema", strict: true, ...} to OpenAI.

OpenAI's structured output requirements for strict: true mode mandate:

  1. additionalProperties: false on all object schemas — schemars does not add this
  2. All fields must appear in required — optional fields (summary, temporal_hint: Option<String>) are generated as non-required by schemars

When these conditions are violated, OpenAI returns 400 Bad Request.

Reproduction

Run graph test with extract_model = "gpt-4o-mini" via ACP. Both conversation turns trigger extraction; all extraction calls fail with:

WARN zeph_memory::semantic: graph extraction failed: LLM error: OpenAI API request failed (status 400 Bad Request)

Graph works in CLI mode with Claude Haiku (Claude handles $defs/optional differently).

Fix

cached_schema::<T>() must post-process the generated schema before sending to OpenAI:

  1. Recursively add "additionalProperties": false to all type: "object" schemas
  2. Move all properties to required, and for Option<T> fields use anyOf: [{...T schema}, {"type": "null"}]

The Gemini provider already handles schema normalization via normalize_schema() in gemini.rs (PR #1635). A similar transform is needed for OpenAI's structured output path.

Alternatively: use response_format: {type: "json_object"} (no-strict mode) with explicit schema in system prompt for extraction — this avoids strict-mode requirements and works with all OpenAI models.

Impact

Severity

High — graph memory feature non-functional with OpenAI providers

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingmemoryzeph-memory crate (SQLite)

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions