astrid-runtime/astrid · error

ASTRID_WORKSPACE_STATE_DIR must be valid UTF-8

Error message

ASTRID_WORKSPACE_STATE_DIR must be valid UTF-8

What it means

`run` reads ASTRID_WORKSPACE_STATE_DIR from the environment and requires it to be valid UTF-8 before constructing a WorkspaceLayout. If the variable is set but contains non-Unicode bytes, the daemon cannot turn it into a Rust String/path safely and bails with this error instead of silently mangling the path.

Solutions

  1. Unset ASTRID_WORKSPACE_STATE_DIR to use the default workspace layout.
  2. Re-set the variable with a valid UTF-8 path: `export ASTRID_WORKSPACE_STATE_DIR=/home/user/.astrid/state`.
  3. Inspect the raw bytes (`env | grep -a ASTRID_WORKSPACE_STATE_DIR | od -c`) and fix the source that wrote them.
  4. Fix the script/exporter that injects the variable so it emits UTF-8.

Example fix

// before
export ASTRID_WORKSPACE_STATE_DIR=$(printf '\xff\xfe/state')   # invalid bytes
// after
export ASTRID_WORKSPACE_STATE_DIR="$HOME/.astrid/state"        # valid UTF-8
Defensive patterns

Strategy: validation

Validate before calling

fn workspace_state_dir_is_utf8() -> bool {
    match std::env::var("ASTRID_WORKSPACE_STATE_DIR") {
        Err(std::env::VarError::NotPresent) => true,
        Ok(_) => true,
        Err(std::env::VarError::NotUnicode(_)) => false,
    }
}

Try / catch

match daemon_run() {
    Err(e) if e.to_string().contains("must be valid UTF-8") => {
        eprintln!("{e:#}; unset ASTRID_WORKSPACE_STATE_DIR or re-export with a UTF-8 path");
        std::process::exit(1);
    }
    other => other,
}

Prevention

When it happens

Trigger: Starting the daemon with ASTRID_WORKSPACE_STATE_DIR set to bytes that are not valid UTF-8 (e.g. raw Latin-1 filenames, shell mangling from a corrupted script, binary garbage in the environment).

Common situations: Environments assembled on systems with non-UTF-8 locale/filenames; env vars copied through tools that transcode incorrectly; paths containing emoji/legacy encodings on filesystems that don't enforce UTF-8.

Understand the failure class

Background: "is not a valid" / "Invalid ... value" environment variable errors: how libraries validate env vars and what to do when they reject yours — this error's family across 48 libraries.

Related errors


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

Appendix: source

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

/// binary and the `astrid` CLI's bundled daemon binary.
///
/// # Errors
///
/// Returns an error if the kernel fails to boot, the native local uplink cannot
/// claim its listener, or the readiness file cannot be written.
#[cfg(unix)]
#[expect(
    clippy::too_many_lines,
    reason = "boot sequence: sequential config resolution + kernel/capsule setup that does not benefit from splitting"
)]
pub async fn run() -> Result<()> {
    let args = Args::parse();
    let workspace_layout = match std::env::var("ASTRID_WORKSPACE_STATE_DIR") {
        Ok(value) => astrid_core::dirs::WorkspaceLayout::new(value)
            .context("invalid ASTRID_WORKSPACE_STATE_DIR")?,
        Err(std::env::VarError::NotPresent) => astrid_core::dirs::WorkspaceLayout::default(),
        Err(std::env::VarError::NotUnicode(_)) => {
            anyhow::bail!("ASTRID_WORKSPACE_STATE_DIR must be valid UTF-8")
        },
    };
    let astrid_home =
        astrid_core::dirs::AstridHome::resolve().context("Failed to resolve Astrid home")?;

    let workspace_root = args.workspace.clone().unwrap_or_else(|| {
        std::env::current_dir().unwrap_or_else(|_| std::path::PathBuf::from("."))
    });

    // Load the unified config once: it drives both logging and the capsule
    // runtime concurrency ceilings below.
    let unified_cfg = astrid_config::Config::load_with_home_and_layout(
        Some(&workspace_root),
        astrid_home.root(),
        &workspace_layout,
    )
    .ok()
    .map(|r| r.config);

View on GitHub (pinned to affd8760f4)