{"record":{"id":"94359e17e2081e2e","repo":"ArchiveBox/ArchiveBox","slug":"refusing-to-start-a-nested-supervisord-from-inside","errorCode":null,"errorMessage":"Refusing to start a nested supervisord from inside a supervisord-managed worker","messagePattern":"Refusing to start a nested supervisord from inside a supervisord-managed worker","errorType":"exception","errorClass":"RuntimeError","httpStatus":null,"severity":"error","filePath":"archivebox/workers/supervisord_util.py","lineNumber":920,"sourceCode":"                PID_FILE.unlink(missing_ok=True)\n                SOCK_FILE.unlink(missing_ok=True)\n        except (OSError, RuntimeError, ValueError) as err:\n            _warn_background_cleanup(\"Could not clear owned supervisord pid/socket files\", err)\n        _supervisord_proc = None\n    return True\n\n\ndef reap_foreground_supervisord_process() -> None:\n    \"\"\"Reap the supervisord child owned by this foreground parent if it exited.\"\"\"\n\n    global _supervisord_proc\n    if _supervisord_proc and _supervisord_proc.poll() is not None:\n        _supervisord_proc = None\n\n\ndef start_new_supervisord_process(daemonize=False):\n    if os.environ.get(\"SUPERVISOR_SERVER_URL\"):\n        raise RuntimeError(\"Refusing to start a nested supervisord from inside a supervisord-managed worker\")\n\n    SOCK_FILE = get_sock_file()\n    WORKERS_DIR = SOCK_FILE.parent / WORKERS_DIR_NAME\n    LOG_FILE = CONSTANTS.LOGS_DIR / LOG_FILE_NAME\n    CONFIG_FILE = SOCK_FILE.parent / CONFIG_FILE_NAME\n    PID_FILE = SOCK_FILE.parent / PID_FILE_NAME\n    stop_grace_seconds = configured_stopwaitsecs(tuple(_desired_supervisord_workers.values()))\n\n    print(f\"[🦸‍♂️] Supervisord starting{' in background' if daemonize else ''}...\")\n    pretty_log_path = pretty_path(LOG_FILE)\n    print(f\"    > Writing supervisord logs to: {pretty_log_path}\")\n    print(f\"    > Writing task worker logs to: {pretty_log_path.replace('supervisord.log', 'worker_*.log')}\")\n    print(f\"    > Using supervisord config file: {pretty_path(CONFIG_FILE)}\")\n    print(f\"    > Using supervisord UNIX socket: {pretty_path(SOCK_FILE)}\")\n    print()\n\n    # clear out existing stale state files\n    shutil.rmtree(WORKERS_DIR, ignore_errors=True)","sourceCodeStart":902,"sourceCodeEnd":938,"githubUrl":"https://github.com/ArchiveBox/ArchiveBox/blob/74564b28220090664f919479e82cbf454125fa34/archivebox/workers/supervisord_util.py#L902-L938","documentation":"Supervisord-managed workers already run under a supervisor, whose presence is signaled by the SUPERVISOR_SERVER_URL env var supervisord injects. start_new_supervisord_process refuses to spawn a nested supervisord in that case, since each worker would otherwise try to become its own daemon.","triggerScenarios":"Code invoked from within a supervisord-managed worker process (SUPERVISOR_SERVER_URL set) that calls start_new_supervisord_process directly — typically via get_or_create_supervisord_process — instead of connecting to the inherited supervisor over RPC.","commonSituations":"Running `archivebox server` or `archivebox run` inside a worker managed by an external/legacy supervisord; custom supervisor setups that set SUPERVISOR_SERVER_URL but whose socket ArchiveBox can't reach; CI wrappers that export supervisor variables.","solutions":["Use get_or_create_supervisord_process instead of start_new_supervisord_process so it connects to the inherited supervisor first","Ensure the inherited SUPERVISOR_SERVER_URL socket is reachable and exposes rpcinterface (supervisord.conf [unix_http_server]/[rpcinterface:supervisor]) — then the guard won't be hit via get_or_create path","Unset SUPERVISOR_SERVER_URL if this process should genuinely own a new supervisord and is not managed by one","Run the command outside of a supervisord-managed program (e.g. directly in a shell/systemd unit rather than as a supervisor program)"],"exampleFix":"// before: nested start inside a managed worker\nenv SUPERVISOR_SERVER_URL=... archivebox ... start_new_supervisord_process()\n// after: connect-or-create via the safe entry point\nsupervisor = get_or_create_supervisord_process()","handlingStrategy":"validation","validationCode":"import os\nif os.environ.get('SUPERVISOR_SERVER_URL'):\n    raise SystemExit('already inside a supervisord-managed worker; use get_or_create_supervisord_process (RPC) instead of starting a new daemon')","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Inside managed workers, always connect via supervisor RPC rather than spawning daemons","Do not define archivebox server/run as supervisord programs in external supervisor configs","Strip SUPERVISOR_SERVER_URL in wrappers/CI if the process must own its own daemon","Remember supervisord itself injects SUPERVISOR_SERVER_URL into children — any child must not re-spawn"],"tags":["supervisord","nesting","environment","daemon"],"backgroundTag":"nested-supervisor-refused","analyzedSha":"74564b28220090664f919479e82cbf454125fa34","analyzedAt":"2026-08-28T23:56:51.556Z","schemaVersion":2},"datasetVersion":"2026-08-29T02:17:18.158Z"}