{"record":{"id":"74465e5807354f0e","repo":"bytedance/deer-flow","slug":"request-config-configurable-must-be-an-object","errorCode":null,"errorMessage":"request config configurable must be an object","messagePattern":"request config configurable must be an object","errorType":"http","errorClass":"HTTPException","httpStatus":400,"severity":"warning","filePath":"backend/app/gateway/services.py","lineNumber":980,"sourceCode":"            \"checkpoint_ns\": checkpoint_ns,\n            \"checkpoint_id\": str(checkpoint_id),\n        }\n    }\n    if checkpoint_map is not None:\n        read_config[\"configurable\"][\"checkpoint_map\"] = checkpoint_map\n\n    checkpointer = get_checkpointer(request)\n    try:\n        checkpoint_tuple = await checkpointer.aget_tuple(read_config)\n    except Exception as exc:\n        logger.exception(\"Failed to validate checkpoint %s for thread %s\", checkpoint_id, sanitize_log_param(thread_id))\n        raise HTTPException(status_code=500, detail=\"Failed to validate checkpoint\") from exc\n    if checkpoint_tuple is None:\n        raise HTTPException(status_code=404, detail=f\"Checkpoint {checkpoint_id} not found\")\n\n    configurable = config.setdefault(\"configurable\", {})\n    if not isinstance(configurable, dict):\n        raise HTTPException(status_code=400, detail=\"request config configurable must be an object\")\n    configurable[\"thread_id\"] = thread_id\n    configurable[\"checkpoint_ns\"] = checkpoint_ns\n    configurable[\"checkpoint_id\"] = str(checkpoint_id)\n    if checkpoint_map is not None:\n        configurable[\"checkpoint_map\"] = checkpoint_map\n\n\nasync def ensure_checkpoint_history_seeded(\n    request: Request,\n    *,\n    thread_id: str,\n    assistant_id: str | None,\n) -> None:\n    \"\"\"Backfill an empty run-event feed from an existing checkpoint head.\n\n    No-op unless the feed is empty AND a checkpoint head with messages\n    exists — i.e. a legacy checkpoint-only thread facing its first journaled\n    run. This is a migration shim: remove it once pre-journal threads are no","sourceCodeStart":962,"sourceCodeEnd":998,"githubUrl":"https://github.com/bytedance/deer-flow/blob/1dd6ba1acb03700589994b0366c5d1c7d05e2eff/backend/app/gateway/services.py#L962-L998","documentation":"HTTP 400 raised when the run's config.configurable is present but not an object — the checkpoint reference is valid, but the request config that must carry thread/checkpoint keys is malformed. The gateway needs a dict to attach thread_id, checkpoint_ns, checkpoint_id, and checkpoint_map into config.configurable.","triggerScenarios":"Sending \"config\": {\"configurable\": \"thread-123\"} or configurable: [\"a\",\"b\"] together with a checkpoint reference.","commonSituations":"Clients modeling configurable as a string thread id (a plausible shorthand); passing a serialized JSON string of the configurable object; schema confusion between config.configurable and config.metadata.","solutions":["Make config.configurable a JSON object: {\"configurable\": {\"thread_id\": \"...\"}}.","Or omit config entirely when you have nothing to put in configurable — the gateway sets the required keys itself."],"exampleFix":"# before\n{\"config\": {\"configurable\": \"t1\"}, \"checkpoint_id\": \"cp1\", \"input\": {...}}\n\n# after\n{\"config\": {\"configurable\": {\"thread_id\": \"t1\"}}, \"checkpoint_id\": \"cp1\", \"input\": {...}}","handlingStrategy":"type-guard","validationCode":"const cfg = payload.config?.configurable;\nif (cfg !== undefined && (typeof cfg !== 'object' || cfg === null || Array.isArray(cfg))) {\n  throw new TypeError('config.configurable must be an object');\n}","typeGuard":"const isConfigurable = (c: unknown): c is Record<string, unknown> =>\n  typeof c === 'object' && c !== null && !Array.isArray(c);","tryCatchPattern":null,"preventionTips":["Omit config.configurable entirely when there is nothing to configure.","Type the run payload so configurable is Record<string, unknown> | undefined."],"tags":["runs","http-400","config","checkpoints"],"backgroundTag":null,"analyzedSha":"1dd6ba1acb03700589994b0366c5d1c7d05e2eff","analyzedAt":"2026-08-14T21:20:34.804Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}