{"record":{"id":"74fa3c1a82d58d99","repo":"bytedance/deer-flow","slug":"gateway-workers-workers-requires-run-events-back","errorCode":null,"errorMessage":"GATEWAY_WORKERS={workers} requires run_events.backend='db', but run_events.backend is '{run_events_backend}'. Memory and JSONL event stores are process-local, so delivery receipt singleton guarantees cannot hold across workers. Set GATEWAY_WORKERS=1 or configure run_events.backend: db.","messagePattern":"GATEWAY_WORKERS=(.+?) requires run_events\\.backend='db', but run_events\\.backend is '(.+?)'\\. Memory and JSONL event stores are process-local, so delivery receipt singleton guarantees cannot hold across workers\\. Set GATEWAY_WORKERS=1 or configure run_events\\.backend: db\\.","errorType":"console","errorClass":"SystemExit","httpStatus":null,"severity":"critical","filePath":"backend/app/gateway/deps.py","lineNumber":115,"sourceCode":"    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.\"\n        )\n\n\ndef _validate_agent_storage(config: AppConfig) -> None:\n    \"\"\"Fail fast on an agent-storage backend the database cannot support.\n","sourceCodeStart":97,"sourceCodeEnd":133,"githubUrl":"https://github.com/bytedance/deer-flow/blob/1dd6ba1acb03700589994b0366c5d1c7d05e2eff/backend/app/gateway/deps.py#L97-L133","documentation":"SystemExit raised at startup when GATEWAY_WORKERS>1 but run_events.backend is not 'db'. Memory and JSONL run-event stores are process-local: with multiple workers, the delivery-receipt singleton guarantee (an event delivered exactly once across the fleet) cannot hold because workers cannot see each other's receipts. The gate forces the shared DB store before multi-worker mode is allowed.","triggerScenarios":"GATEWAY_WORKERS>1 with run_events.backend set to memory or jsonl (or defaulted to a non-db value); reached after the postgres-backend check passes.","commonSituations":"Default run_events configuration never changed when workers were scaled; JSONL store chosen for debugging/inspection and left on; config drift between single-worker dev and multi-worker prod.","solutions":["Set run_events.backend: db in config.yaml","Or set GATEWAY_WORKERS=1","Restart the Gateway"],"exampleFix":"# config.yaml\n# before\nrun_events:\n  backend: jsonl\n# after\nrun_events:\n  backend: db","handlingStrategy":"validation","validationCode":"workers = int(os.environ.get(\"GATEWAY_WORKERS\", \"1\"))\nre_backend = getattr(getattr(load_config(), \"run_events\", None), \"backend\", None)\nassert not (workers > 1 and re_backend != \"db\"), \"multi-worker needs run_events.backend: db\"","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Switch run_events to db before scaling workers — memory/jsonl receipts are process-local","Reserve jsonl backend for single-worker debugging sessions","Add a config-lint step to CI that fails on multi-worker-incompatible backends"],"tags":["config","startup","run-events","workers","exactly-once","system-exit","gateway"],"backgroundTag":null,"analyzedSha":"1dd6ba1acb03700589994b0366c5d1c7d05e2eff","analyzedAt":"2026-08-14T21:20:34.804Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}