{"record":{"id":"bff942289ae10b73","repo":"bytedance/deer-flow","slug":"scheduler-multi-instance-true-requires-run-ownersh","errorCode":null,"errorMessage":"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.","messagePattern":"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\\.","errorType":"console","errorClass":"SystemExit","httpStatus":null,"severity":"critical","filePath":"backend/app/gateway/deps.py","lineNumber":100,"sourceCode":"    try:\n        workers = int(os.environ.get(\"GATEWAY_WORKERS\", \"1\"))\n    except (TypeError, ValueError):\n        workers = 1\n\n    scheduler = getattr(config, \"scheduler\", None)\n    multi_instance_requested = bool(getattr(scheduler, \"multi_instance\", False))\n    multi_instance_scheduler = bool(getattr(scheduler, \"enabled\", False) and multi_instance_requested)\n\n    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.\"","sourceCodeStart":82,"sourceCodeEnd":118,"githubUrl":"https://github.com/bytedance/deer-flow/blob/1dd6ba1acb03700589994b0366c5d1c7d05e2eff/backend/app/gateway/deps.py#L82-L118","documentation":"SystemExit raised at startup when scheduler.multi_instance=true but run_ownership is missing or run_ownership.heartbeat_enabled is not true. Peer schedulers reconcile orphaned runs; without heartbeats every run has a NULL lease and would look orphaned, so one scheduler would kill another scheduler's live runs on every reconcile pass. The gate forces a valid lease protocol before multi-instance mode is allowed.","triggerScenarios":"config.yaml with scheduler.multi_instance: true and either no run_ownership section or run_ownership.heartbeat_enabled: false.","commonSituations":"Config written before run-ownership existed (upgrade path); hand-merged config.yaml dropping the run_ownership block; disabling heartbeats to 'reduce load' while scaling out schedulers.","solutions":["Set run_ownership.heartbeat_enabled: true in config.yaml","Or set scheduler.multi_instance: false","Restart the Gateway"],"exampleFix":"# config.yaml\n# before\nrun_ownership:\n  heartbeat_enabled: false\n# after\nrun_ownership:\n  heartbeat_enabled: true","handlingStrategy":"validation","validationCode":"cfg = load_config()\nmi = bool(getattr(getattr(cfg, \"scheduler\", None), \"multi_instance\", False))\nro = getattr(cfg, \"run_ownership\", None)\nassert not (mi and (ro is None or not ro.heartbeat_enabled)), \"multi_instance needs heartbeat_enabled\"","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Never disable run_ownership heartbeats on multi-node deployments","After upgrading, grep config.yaml for run_ownership — upgrades add required sections","Bundle the three multi_instance prerequisites into one reviewed config change"],"tags":["config","startup","scheduler","run-ownership","heartbeat","system-exit","gateway"],"backgroundTag":null,"analyzedSha":"1dd6ba1acb03700589994b0366c5d1c7d05e2eff","analyzedAt":"2026-08-14T21:20:34.804Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}