{"record":{"id":"30ad89c7b1dfa8a3","repo":"bytedance/deer-flow","slug":"gateway-workers-workers-cannot-enable-agentic-br","errorCode":null,"errorMessage":"GATEWAY_WORKERS={workers} cannot enable agentic browser tools: browser sessions are process-local and uvicorn does not provide thread affinity. Set GATEWAY_WORKERS=1 or disable the browser_navigate tool.","messagePattern":"GATEWAY_WORKERS=(.+?) cannot enable agentic browser tools: browser sessions are process-local and uvicorn does not provide thread affinity\\. Set GATEWAY_WORKERS=1 or disable the browser_navigate tool\\.","errorType":"console","errorClass":"SystemExit","httpStatus":null,"severity":"critical","filePath":"backend/app/gateway/deps.py","lineNumber":109,"sourceCode":"    backend = getattr(config.database, \"backend\", None)\n    run_events_backend = getattr(getattr(config, \"run_events\", None), \"backend\", None)\n    run_ownership = getattr(config, \"run_ownership\", None)\n\n    if multi_instance_requested and backend != \"postgres\":\n        raise SystemExit(f\"scheduler.multi_instance=true requires database.backend='postgres'. database.backend is '{backend}'. Set scheduler.multi_instance=false or configure Postgres.\")\n    if multi_instance_requested and run_events_backend != \"db\":\n        raise SystemExit(f\"scheduler.multi_instance=true requires run_events.backend='db'. run_events.backend is '{run_events_backend}'. Set scheduler.multi_instance=false or configure run_events.backend: db.\")\n    if multi_instance_requested and (run_ownership is None or not run_ownership.heartbeat_enabled):\n        raise SystemExit(\"scheduler.multi_instance=true requires run_ownership.heartbeat_enabled=true so peer runs retain a valid lease. Set scheduler.multi_instance=false or enable run ownership heartbeats.\")\n\n    if workers <= 1:\n        return\n\n    if config.scheduler.enabled and not multi_instance_scheduler:\n        raise SystemExit(f\"GATEWAY_WORKERS={workers} cannot run with scheduler.enabled=true because each worker starts its own scheduler. Set GATEWAY_WORKERS=1, scheduler.multi_instance=true, or scheduler.enabled=false.\")\n\n    if _browser_tools_enabled_in_config(config):\n        raise SystemExit(browser_multi_worker_error(workers))\n\n    if backend != \"postgres\":\n        raise SystemExit(f\"GATEWAY_WORKERS={workers} requires database.backend='postgres', but database.backend is '{backend}'. SQLite cannot support concurrent multi-process access. Set GATEWAY_WORKERS=1 or switch to Postgres.\")\n\n    if run_events_backend != \"db\":\n        raise SystemExit(\n            f\"GATEWAY_WORKERS={workers} requires run_events.backend='db', but run_events.backend is '{run_events_backend}'. \"\n            \"Memory and JSONL event stores are process-local, so delivery receipt singleton guarantees cannot hold across workers. \"\n            \"Set GATEWAY_WORKERS=1 or configure run_events.backend: db.\"\n        )\n\n    if run_ownership is None or not run_ownership.heartbeat_enabled:\n        raise SystemExit(\n            f\"GATEWAY_WORKERS={workers} requires run_ownership.heartbeat_enabled=true. \"\n            \"Without heartbeat, every run has a NULL lease, so reconciliation \"\n            \"treats all inflight runs as orphans — Worker B would kill Worker A's \"\n            \"live runs on every rolling update or scale-up. \"\n            \"Set run_ownership.heartbeat_enabled=true in config.yaml.\"","sourceCodeStart":91,"sourceCodeEnd":127,"githubUrl":"https://github.com/bytedance/deer-flow/blob/1dd6ba1acb03700589994b0366c5d1c7d05e2eff/backend/app/gateway/deps.py#L91-L127","documentation":"SystemExit raised at startup when GATEWAY_WORKERS>1 and browser tools are enabled in config: browser sessions are process-local and uvicorn gives no thread/worker affinity, so a browser_navigate session created on worker A cannot be driven by a request routed to worker B. The gate (via browser_multi_worker_error) fails fast instead of letting sessions break non-deterministically under the load balancer.","triggerScenarios":"GATEWAY_WORKERS>1 with the browser_navigate tool / browser tools enabled in config.yaml (detected by _browser_tools_enabled_in_config).","commonSituations":"Scaling out workers for capacity on a deployment that demos browser automation; enabling browser tools on an existing multi-worker production config; container images with a high default GATEWAY_WORKERS.","solutions":["Set GATEWAY_WORKERS=1","Or disable the browser_navigate tool in config.yaml","If browser automation at scale is needed, run it in a separate single-worker deployment"],"exampleFix":"# environment\n# before\nGATEWAY_WORKERS=4\n# after\nGATEWAY_WORKERS=1","handlingStrategy":"validation","validationCode":"workers = int(os.environ.get(\"GATEWAY_WORKERS\", \"1\"))\nassert not (workers > 1 and browser_tools_enabled(load_config())), \"browser tools require GATEWAY_WORKERS=1\"","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Run browser-tool-enabled deployments single-worker or on a dedicated instance","Disable browser_navigate in base config and enable it only where needed","Remember uvicorn routes requests to workers without affinity — anything process-local breaks at N>1"],"tags":["config","startup","browser-tools","workers","scaling","system-exit","gateway"],"backgroundTag":null,"analyzedSha":"1dd6ba1acb03700589994b0366c5d1c7d05e2eff","analyzedAt":"2026-08-14T21:20:34.804Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}