HKUDS/DeepTutor · error · ValueError

Capability config must be an object.

Error message

Capability config must be an object.

What it means

_clean_public_config rejects a request-level capability config that is not a JSON object/dict. Configs arriving as lists, strings, numbers, or booleans (anything non-None non-dict) raise this ValueError before Pydantic validation runs.

Source

Thrown at deeptutor/runtime/request_contracts.py:78

        "chartjs",
        "mermaid",
        "html",
        "manim_video",
        "manim_image",
    ] = "auto"
    # Only meaningful when the routed render_type is manim_video / manim_image
    # (either chosen explicitly or selected by AnalysisAgent in auto mode).
    # Mirrors MathAnimatorRequestConfig defaults so the auto path stays
    # zero-config.
    quality: Literal["low", "medium", "high"] = "medium"
    style_hint: str = Field(default="", max_length=500)


def _clean_public_config(raw_config: dict[str, Any] | None) -> dict[str, Any]:
    if raw_config is None:
        return {}
    if not isinstance(raw_config, dict):
        raise ValueError("Capability config must be an object.")
    cleaned = dict(raw_config)
    for key in _RUNTIME_ONLY_KEYS:
        cleaned.pop(key, None)
    return cleaned


def _validate_model(
    model_type: type[BaseModel],
    raw_config: dict[str, Any] | None,
    *,
    label: str,
) -> BaseModel:
    cleaned = _clean_public_config(raw_config)
    try:
        return model_type.model_validate(cleaned)
    except ValidationError as exc:
        details = "; ".join(
            f"{'.'.join(str(part) for part in error['loc'])}: {error['msg']}"

View on GitHub (pinned to 3e82f13042)

Solutions

  1. Make the request's config field a JSON object, e.g. {"config": {"render_mode": "svg"}}
  2. If config is double-encoded JSON, parse it once before sending
  3. Omit config entirely (null is accepted and treated as {}) when you have no config

Example fix

# before
{"config": "{\"render_mode\": \"svg\"}"}
# after
{"config": {"render_mode": "svg"}}
Defensive patterns

Strategy: type-guard

Validate before calling

if config is not None and not isinstance(config, dict):
    raise TypeError("config must be an object or null")
# or if it might be a JSON string:
import json
if isinstance(config, str):
    config = json.loads(config)

Type guard

def is_valid_config_shape(cfg: object) -> bool:
    return cfg is None or isinstance(cfg, dict)

Try / catch

try:
    validate_chat_request_config(cfg)
except ValueError as e:
    if "must be an object" in str(e):
        cfg = {}  # or re-shape client payload
        result = validate_chat_request_config(cfg)

Prevention

When it happens

Trigger: Sending a chat/deep_solve/deep_question/visualize request (via WebSocket API or SDK) with `config` set to e.g. a JSON array, a bare string, or a number instead of an object.

Common situations: Frontend sending JSON where config is double-encoded (a JSON string containing JSON); clients constructing the payload with the wrong shape; SDK users passing a list of options instead of a dict; copy-paste errors from YAML configs pasted as strings.

Related errors


AI-assisted analysis of HKUDS/DeepTutor@3e82f13042 (2026-08-27). Data as JSON: /api/errors/a436be3eae6b592d. Report an issue: GitHub.