astrid-runtime/astrid · critical · anyhow::Error

Failed to write readiness file (daemon is useless without…

Error message

Failed to write readiness file (daemon is useless without it): {e}

What it means

The daemon writes a readiness file for the workspace (`write_readiness_file_for_workspace`) so clients can discover it. The write is executed in a race-tolerant block, and if it fails the daemon treats itself as useless and aborts with this message, since nothing can connect to a daemon whose readiness file is absent.

Solutions

  1. Check the wrapped `{e}` I/O error for the concrete cause.
  2. Ensure the workspace root and its layout directories are writable by the daemon user.
  3. Free disk space / fix quota issues, then restart the daemon.
Defensive patterns

Strategy: retry

Validate before calling

// shell
[ -w "$WORKSPACE_ROOT" ] || { echo "workspace not writable" >&2; exit 1; }
[ "$(df --output=avail "$WORKSPACE_ROOT" | tail -1)" -gt 1024 ] || { echo "low disk" >&2; exit 1; }

Try / catch

// rust
if let Err(e) = daemon::run(args).await {
    if e.to_string().contains("readiness file") {
        eprintln!("fix workspace write access/disk space, then retry: {e:#}");
    }
    std::process::exit(1);
}

Prevention

When it happens

Trigger: Daemon `run()` reaching the readiness-file step where the filesystem write fails: unwritable directory, disk full, or the workspace layout has no valid target path.

Common situations: Read-only filesystem or changed permissions on the workspace/durable root after the daemon started; disk quota exhaustion on CI machines.

Understand the failure class

Background: "failed to write file", "Could not save figure", "Error saving remote file" — file write failed: causes and fixes across languages and libraries — this error's family across 38 libraries.

Related errors


AI-assisted analysis of astrid-runtime/astrid@affd8760f4 (2026-09-09). Data as JSON: /api/errors/5f7eb5eed6c6b0a0. Report an issue: GitHub.

Appendix: source

Thrown at crates/astrid-daemon/src/lib.rs:365

                error = %error,
                principal = %install_principal,
                "install principal is not admitted; canonical astrid-contracts.wit was not refreshed"
            );
        },
    }

    // Signal readiness AFTER the default CLI/system view is loaded and
    // accepting connections. The CLI polls for this file to avoid connecting
    // before the handshake accept loop is running.
    write_readiness_then_arm_ephemeral(
        args.ephemeral,
        || {
            astrid_kernel::socket::write_readiness_file_for_workspace(
                &kernel.workspace_root,
                kernel.workspace_layout(),
            )
            .map_err(|e| {
                anyhow::anyhow!(
                    "Failed to write readiness file \
                     (daemon is useless without it): {e}"
                )
            })
        },
        || {
            // Only now can a spawning client connect. Starting this timer
            // during Kernel construction lets a cold capsule boot consume
            // the entire grace period and makes the daemon advertise
            // readiness after shutdown was already requested.
            kernel.arm_ephemeral_startup_fallback();
        },
    )?;

    tracing::info!(
        session = %session_id.0,
        ephemeral = args.ephemeral,
        "Kernel booted successfully"

View on GitHub (pinned to affd8760f4)