{"record":{"id":"f87d73024b3f543a","repo":"bytedance/deer-flow","slug":"configuration-not-available","errorCode":null,"errorMessage":"Configuration not available","messagePattern":"Configuration not available","errorType":"http","errorClass":"HTTPException","httpStatus":503,"severity":"error","filePath":"backend/app/gateway/deps.py","lineNumber":362,"sourceCode":"    (engines, sandbox provider, IM channels, logging handler) require a\n    process restart to change at runtime. The authoritative list lives in\n    :mod:`deerflow.config.reload_boundary` and is mirrored by the\n    standardised ``\"startup-only:\"`` prefix on the matching\n    ``Field(description=...)`` in :class:`AppConfig` — IDE hover on those\n    fields will surface the boundary inline. See\n    ``backend/CLAUDE.md`` \"Config Hot-Reload Boundary\" for the operator\n    summary.\n\n    Any failure to materialise the config (missing file, permission denied,\n    YAML parse error, validation error) is reported as 503 — semantically\n    \"the gateway cannot serve requests without a usable configuration\" — and\n    logged with the original exception so operators have something to debug.\n    \"\"\"\n    try:\n        return get_app_config()\n    except Exception as exc:  # noqa: BLE001 - request boundary: log and degrade gracefully\n        logger.exception(\"Failed to load AppConfig at request time\")\n        raise HTTPException(status_code=503, detail=\"Configuration not available\") from exc\n\n\n@asynccontextmanager\nasync def langgraph_runtime(app: FastAPI, startup_config: AppConfig) -> AsyncGenerator[None, None]:\n    \"\"\"Bootstrap and tear down all LangGraph runtime singletons.\n\n    ``startup_config`` is the ``AppConfig`` snapshot taken once during\n    ``lifespan()`` for one-shot infrastructure bootstrap. The engines and\n    stores constructed here (stream bridge, persistence engine, checkpointer,\n    store, run-event store) are restart-required by design — they hold live\n    connections, file handles, or singleton providers — so they bind to this\n    snapshot and survive across `config.yaml` edits. Request-time consumers\n    must still go through :func:`get_config` for any field that should be\n    hot-reloadable. See ``backend/CLAUDE.md`` \"Config Hot-Reload Boundary\".\n\n    The matching ``run_events_config`` is frozen onto ``app.state`` so\n    :func:`get_run_context` pairs a freshly-loaded ``AppConfig`` with the\n    *startup-time* run-events configuration the underlying ``event_store``","sourceCodeStart":344,"sourceCodeEnd":380,"githubUrl":"https://github.com/bytedance/deer-flow/blob/1dd6ba1acb03700589994b0366c5d1c7d05e2eff/backend/app/gateway/deps.py#L344-L380","documentation":"Raised as HTTP 503 by the Gateway when the AppConfig cannot be materialised at request time. get_app_config() is invoked per-request so hot-reload of config.yaml takes effect; any failure to load or validate it (missing file, permission denied, YAML parse error, schema validation error) is wrapped into HTTPException(503, 'Configuration not available') with the original exception logged server-side.","triggerScenarios":"Any Gateway REST API request made while config.yaml is missing, unreadable (bad permissions), contains invalid YAML syntax, or fails AppConfig schema validation. Also triggered if the process's working directory changed so the config path no longer resolves, or if config.yaml was edited mid-request into a broken state.","commonSituations":"Operator edits config.yaml live and saves a half-typed file (hot-reload picks up the broken snapshot); fresh clone without running `make config` to copy config.example.yaml to config.yaml; file ownership/permission mistakes when running the Gateway under a different user; YAML indentation or duplicate-key mistakes.","solutions":["Check the Gateway logs: the line 'Failed to load AppConfig at request time' includes the original exception (FileNotFoundError, PermissionError, yaml.YAMLError, or ValidationError) which names the exact cause","Validate config.yaml: run `python -c \"from app.config import get_app_config; get_app_config()\"` in backend/ or `make doctor` to surface the validation error directly","Fix the YAML/schema issue named in the logged exception (restore the file, correct permissions, fix indentation/keys)","If config.yaml is absent, copy config.example.yaml to config.yaml and extensions_config.example.json to extensions_config.json, then retry the request (no restart needed since config is read per-request)"],"exampleFix":"# config.yaml broken (e.g. tab indentation) -> 503 on every request\n# fix: validate before the Gateway serves\n# cd backend && python -c \"from app.config import get_app_config; print(get_app_config())\"\n# -> ValidationError: 'models' must not be empty ... correct it, request succeeds without restart","handlingStrategy":"validation","validationCode":"import yaml, pathlib\ncfg = pathlib.Path('config.yaml')\nassert cfg.exists(), 'config.yaml missing — run `make config`'\nyaml.safe_load(cfg.read_text())  # raises on parse error before any HTTP call","typeGuard":"null","tryCatchPattern":"from fastapi import HTTPException\ntry:\n    resp = client.get('/api/...')\nexcept HTTPException as e:\n    if e.status_code == 503 and e.detail == 'Configuration not available':\n        # config-layer failure: surface ops message, do not retry with same config\n        raise SystemExit('Gateway config unusable — check Gateway logs')\n    raise","preventionTips":["Run `make doctor` before starting or probing the stack","Validate config.yaml in CI with a yaml.safe_load + schema check step","Keep config edits atomic: write to a temp file and rename, never save half-edited configs"],"tags":["config","yaml","http-503","gateway","hot-reload"],"backgroundTag":null,"analyzedSha":"1dd6ba1acb03700589994b0366c5d1c7d05e2eff","analyzedAt":"2026-08-14T21:20:34.804Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}