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
- Unset ASTRID_WORKSPACE_STATE_DIR to use the default workspace layout.
- Re-set the variable with a valid UTF-8 path: `export ASTRID_WORKSPACE_STATE_DIR=/home/user/.astrid/state`.
- Inspect the raw bytes (`env | grep -a ASTRID_WORKSPACE_STATE_DIR | od -c`) and fix the source that wrote them.
- 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
- Always export the variable from UTF-8-safe sources (`printf '%s'`, not raw bytes).
- Check env bytes with `env | grep -a VAR | od -c` when debugging encoding issues.
- Unset the variable to fall back to the default workspace layout.
- Ensure build/CI environments use a UTF-8 locale (LANG=C.UTF-8).
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
- ASTRID_ENFORCED_DISTRO must contain a valid UTF-8 distro…
- must be exactly 'file' or 'stderr', got
- Admin request timed out after
- an Astrid daemon appears to be running but its uplink is…
- an Astrid daemon appears to be running but its uplink is…
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)