Skip to content

server : fix json_schema response_format ignored by some chat templates - #21537

Open
wiktoraleksanderkaczor wants to merge 1 commit into
ggml-org:masterfrom
wiktoraleksanderkaczor:fix-json-schema-fallback
Open

server : fix json_schema response_format ignored by some chat templates#21537
wiktoraleksanderkaczor wants to merge 1 commit into
ggml-org:masterfrom
wiktoraleksanderkaczor:fix-json-schema-fallback

Conversation

@wiktoraleksanderkaczor

@wiktoraleksanderkaczor wiktoraleksanderkaczor commented Apr 7, 2026

Copy link
Copy Markdown

Overview

response_format with type: json_schema is silently ignored when the active chat template's specialized handler does not process the json_schema field. The model generates unconstrained text instead of schema-valid JSON.

Affected handlers include at least the LFM2 and LFM2.5 ones. Possibly more... basically any that do not explicitly handle json_schema and write it back into llama_params so it doesn't get lost.

When json_schema is present but the chat template produced an empty grammar for it, pass json_schema through to server-task.cpp's existing json_schema_to_grammar path. Also skip the template's grammar triggers, preserved tokens, generation prompt, and chat parser to avoid conflicts.

Handlers that already handle json_schema (GPT-OSS, Gemma4, Ministral, autoparser, legacy) produce a non-empty grammar, so the fallback never activates for them.

Additional information

You can reproduce the issue and verify the fix via below command:

llama-server -hf unsloth/LFM2.5-1.2B-Instruct-GGUF:Q8_K_XL --jinja

curl -s http://localhost:8080/v1/chat/completions \
  -H "Content-Type: application/json" \
  -d '{
    "model": "test",
    "messages": [{"role":"user","content":"Say hi"}],
    "response_format": {
      "type": "json_schema",
      "json_schema": {
        "name": "Test",
        "schema": {
          "type": "object",
          "properties": {"greeting": {"type": "string"}},
          "required": ["greeting"],
          "additionalProperties": false
        }
      }
    }
  }'


# Before: "content": "Hello! How can I help you today?"
# After: "content": "{ \"greeting\": \"Hi there!\" }"

Requirements

  • I have read and agree with the contributing guidelines
  • AI usage disclosure: YES — AI was used to help trace the bug through the codebase. Fix was applied by AI after identification and testing done manually.

@ggml-gh-bot

ggml-gh-bot Bot commented Apr 7, 2026

Copy link
Copy Markdown

Hi @wiktoraleksanderkaczor, thanks for your contribution!

Per our contribution guidelines, the automated PR checker found the following issue(s) that need your attention:

  • AI-generated content: This project does not accept PRs, descriptions or commit messages that are fully or predominantly AI-generated. If you have used AI to assist you in writing code, please make sure to disclose that explicitly.

Please note that maintainers reserve the right to make final decisions on PRs. If you believe there is a mistake, please comment below.

@wiktoraleksanderkaczor

Copy link
Copy Markdown
Author

@ngxson @CISC @pwilkin

Tagging y'all directly as the auto-assigned team review doesn't seem to have gone through (I think) given missing page when clicking it via https://github.com/orgs/ggml-org/teams/llama-server

PR fixes response_format: json_schema being silently ignored by chat template handlers that don't explicitly process the json_schema field (LFM2, LFM2.5, likely others). The fix is in tools/server/server-common.cpp and touches the jinja/chat-template → grammar pipeline. I would appreciate a look when you get a chance.

@CISC

CISC commented Apr 10, 2026

Copy link
Copy Markdown
Member

Tagging y'all directly as the auto-assigned team review doesn't seem to have gone through (I think) given missing page when clicking it via https://github.com/orgs/ggml-org/teams/llama-server

It has been assigned correctly, GitHub is just being coy about it. :)

@pwilkin pwilkin left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems OK, just maybe do an extra check here to be safe.


// json_schema fallback: if the chat template did not produce a grammar, pass json_schema
// through to server-task.cpp and skip template grammar artifacts to avoid conflicts.
bool json_schema_passthrough = !json_schema.is_null() && chat_params.grammar.empty();

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Might want to check if the json schema isn't empty and not just null, just in case.

@pwilkin

pwilkin commented Apr 10, 2026

Copy link
Copy Markdown
Member

@aldehir need a second look here, especially on whether bypassing the parser with response schema like this will be OK.

@aldehir

aldehir commented Apr 10, 2026

Copy link
Copy Markdown
Contributor

I think this has the potential to make things worse for certain models, especially reasoning ones, as they will be constrained to not reason and it will break the parsing underneath.

It's simple to implement the response format support to the models that don't currently support it.

@tdakhran

Copy link
Copy Markdown
Contributor

LFM2 issue with structured output was fixed in #24377

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants