sgl-project/sglang · error · ValueError

Cannot combine tool calls with constrained decoding (text.fo

Error message

Cannot combine tool calls with constrained decoding (text.format / regex / ebnf / structural_tag / json_schema). Remove one.

What it means

The Responses-API request converter refuses tool calls combined with any constrained-decoding output constraint (text.format, regex, ebnf, structural_tag, or json_schema params). Both mechanisms compile to XGrammar constraints that would conflict, so the request is rejected rather than silently dropping one.

Source

Thrown at python/sglang/srt/entrypoints/openai/protocol.py:1827

        # Apply any additional default parameters
        for key, value in default_params.items():
            if key not in params or params[key] is None:
                params[key] = value

        json_schema = self._json_schema_from_text_format(self.text)
        if json_schema is not None:
            params["json_schema"] = json_schema

        has_existing_constraints = (
            params.get("regex")
            or params.get("ebnf")
            or params.get("structural_tag")
            or params.get("json_schema")
        )
        if tool_call_constraint and has_existing_constraints:
            # Refuse rather than silently drop the tool-call grammar.
            raise ValueError(
                "Cannot combine tool calls with constrained decoding "
                "(text.format / regex / ebnf / structural_tag / json_schema). "
                "Remove one."
            )
        if tool_call_constraint:
            constraint_type, constraint_value = tool_call_constraint
            if constraint_type in ("structural_tag", "json_schema"):
                params[constraint_type] = convert_json_schema_to_str(
                    constraint_value.model_dump(by_alias=True)
                    if hasattr(constraint_value, "model_dump")
                    else constraint_value
                )
            else:
                params[constraint_type] = constraint_value

        return params

View on GitHub (pinned to 0132848349)

Solutions

  1. Drop text.format/regex/ebnf/structural_tag/json_schema from the request and constrain arguments via the tool's parameters schema
  2. Or remove tools/tool_choice if structured text output is what you need

Example fix

// before
{"tools": [...], "tool_choice": "auto", "text": {"format": {"type": "json_schema", ...}}}
// after
{"tools": [...], "tool_choice": "auto"}
Defensive patterns

Strategy: validation

Validate before calling

fmt = (body.get("text") or {}).get("format")
if body.get("tools") and fmt:
    body["text"].pop("format")  # or drop tools

Type guard

def has_output_constraint(text): return bool((text or {}).get('format'))

Try / catch

try: responses.create(...)
except ValueError as e: if 'constrained decoding' in str(e): retry without text.format

Prevention

When it happens

Trigger: POST /v1/responses with tools + tool_choice forcing calls, and text.format={...} or regex/ebnf/structural_tag/json_schema set in text.format params.

Common situations: Wanting schema-validated tool arguments and adding an output schema too; copying structured-output examples into a function-calling app; embedding json_schema in text.format while tools are attached.

Related errors


AI-assisted analysis of sgl-project/sglang@0132848349 (2026-08-28). Data as JSON: /api/errors/05c89fcdbfc462e1. Report an issue: GitHub.