{"record":{"id":"1f2a35b47e257a80","repo":"astrid-runtime/astrid","slug":"daemon-workspace-metadata-was-not-available-within","errorCode":null,"errorMessage":"daemon workspace metadata was not available within {timeout_secs} seconds; run `astrid restart`","messagePattern":"daemon workspace metadata was not available within (.+?) seconds; run `astrid restart`","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/astrid-cli/src/commands/daemon.rs","lineNumber":263,"sourceCode":"    // Default wait only: do not load operator config here. Every admin\n    // command including `agent list --format json` hits this path after\n    // logging is live; Config::load_with_layout would trace to stderr and\n    // poison merged stdout JSON in the crash-recovery smoke.\n    let timeout_secs = default_daemon_ready_secs();\n    let attempts = readiness_attempts(timeout_secs, ready::DAEMON_READY_POLL_MILLIS);\n    for _ in 0..attempts {\n        match std::fs::read_to_string(&ready_path) {\n            Ok(metadata) => return validate_daemon_workspace_metadata(&metadata, &expected),\n            Err(error) if error.kind() == std::io::ErrorKind::NotFound => {\n                tokio::time::sleep(DAEMON_READY_POLL).await;\n            },\n            Err(error) => {\n                return Err(error).context(\"failed to read daemon workspace metadata\");\n            },\n        }\n    }\n\n    anyhow::bail!(\n        \"daemon workspace metadata was not available within {timeout_secs} seconds; run `astrid restart`\"\n    )\n}\n\n/// Spawn a persistent (non-ephemeral) daemon and wait for readiness.\npub(crate) async fn spawn_persistent_daemon() -> Result<()> {\n    let ready_path = socket_client::readiness_path();\n    println!(\n        \"{}\",\n        theme::Theme::info(\"Starting Astrid daemon (persistent mode)...\")\n    );\n    let ws = std::env::current_dir().unwrap_or_else(|_| std::path::PathBuf::from(\".\"));\n    let daemon_bin = find_companion_binary(\"astrid-daemon\")?;\n\n    let mut cmd = std::process::Command::new(daemon_bin);\n    // No --ephemeral flag = persistent mode\n    cmd.env(\n        \"ASTRID_WORKSPACE_STATE_DIR\",","sourceCodeStart":245,"sourceCodeEnd":281,"githubUrl":"https://github.com/astrid-runtime/astrid/blob/affd8760f44190dbdfbec23403f4c4b642c33112/crates/astrid-cli/src/commands/daemon.rs#L245-L281","documentation":"After ensuring a daemon is up, the CLI verifies the daemon's workspace matches the caller's workspace by polling the readiness file, which carries daemon workspace metadata/fingerprints. If the file never appears (or stays unreadable as NotFound) within the default ready timeout, this error is raised. It means the daemon never finished booting far enough to publish its workspace metadata.","triggerScenarios":"ensure_daemon_inner_locked (after spawn or on UseExisting) or handle_start_locked calling ensure_daemon_workspace_matches, and the readiness file is still absent after readiness_attempts(default_daemon_ready_secs()) polls — daemon boot stalled, failed, or a live daemon from another workspace never writes the expected file.","commonSituations":"Daemon crashed mid-boot after the socket connected; a pre-existing daemon serving a different workspace whose metadata never satisfies validation; extremely slow first cutover exceeding the default ready timeout; readiness file deleted or on a flaky mount.","solutions":["Run `astrid restart` as the message advises, then retry the command.","Check the daemon boot log to see whether it failed or is still importing; increase the ready timeout if the import is legitimately slow.","Confirm no other daemon for a different workspace is bound to the endpoint; stop it and start the daemon for the intended workspace.","Verify the readiness file directory exists and is writable (socket/readiness path configuration) if boot logs look healthy."],"exampleFix":"# before\n$ astrid agent list\nError: daemon workspace metadata was not available within 30 seconds; run `astrid restart`\n# after\n$ astrid restart\n$ astrid agent list  # OK","handlingStrategy":"retry","validationCode":"// Poll readiness metadata yourself before issuing commands\nasync fn wait_ready_metadata(ready_path: &Path, secs: u64) -> bool {\n    for _ in 0..secs * 4 {\n        if let Ok(meta) = std::fs::read_to_string(ready_path) {\n            return validate_daemon_workspace_metadata(&meta, &expected).is_ok();\n        }\n        tokio::time::sleep(Duration::from_millis(250)).await;\n    }\n    false\n}","typeGuard":null,"tryCatchPattern":"match ensure_daemon_workspace_matches(workspace_root).await {\n    Err(e) if e.to_string().contains(\"workspace metadata was not available\") => {\n        eprintln!(\"daemon never published workspace metadata; restarting\");\n        astrid_restart().await?;\n        ensure_daemon_workspace_matches(workspace_root).await\n    },\n    other => other,\n}","preventionTips":["Run `astrid restart` whenever readiness metadata lags rather than re-running the failed command against a half-booted daemon.","Increase the ready timeout for large workspaces undergoing first cutover.","Ensure only one daemon per workspace to avoid metadata from the wrong workspace.","Monitor the readiness file's presence/age as a daemon health signal."],"tags":["daemon","readiness","workspace","timeout"],"backgroundTag":"daemon-readiness-timeout","analyzedSha":"affd8760f44190dbdfbec23403f4c4b642c33112","analyzedAt":"2026-09-09T21:28:12.402Z","contentChangedAt":"2026-09-09T21:28:12.402Z","schemaVersion":2},"datasetVersion":"2026-09-14T11:17:12.474Z"}