astrid-runtime/astrid · error · anyhow::Error
required environment variable ASTRID_HOOK_TOKEN is missing…
Error message
required environment variable ASTRID_HOOK_TOKEN is missing or empty
What it means
`hook_token_from_env` reads `ASTRID_HOOK_TOKEN` via `env_lookup` and deliberately never generates a replacement token — the emitting process must echo the token the host provided so hooks are authenticated. If the variable is missing or empty, publishing a hook envelope is refused with this error.
Solutions
- Run the hook through the normal astrid host launch path so it injects `ASTRID_HOOK_TOKEN`.
- If manual invocation is required, copy the token value the host exposed into the environment: `ASTRID_HOOK_TOKEN=<token> <command>`.
- Check for empty-string values (`printenv ASTRID_HOOK_TOKEN`) — empty counts as missing; re-export a real token.
Example fix
// before $ astrid-emit my-topic < payload.json // after $ export ASTRID_HOOK_TOKEN="$TOKEN_FROM_HOST" $ astrid-emit my-topic < payload.json
Defensive patterns
Strategy: validation
Validate before calling
// shell
[ -n "$ASTRID_HOOK_TOKEN" ] || { echo "ASTRID_HOOK_TOKEN must be set (host-injected)" >&2; exit 1; } Try / catch
// rust
let token = match astrid_emit::hook_token_from_env() {
Ok(t) => t,
Err(e) => { eprintln!("launch via the astrid host so ASTRID_HOOK_TOKEN is injected: {e}"); std::process::exit(1); }
}; Prevention
- Always launch hooks/emitters through the astrid host, which injects the token.
- Use `printenv ASTRID_HOOK_TOKEN` to verify non-empty values before manual runs.
- For cron/systemd, export the token in the unit or wrapper environment.
When it happens
Trigger: Calling `hook_token_from_env()` (or the emit path that uses it) in a process where `ASTRID_HOOK_TOKEN` is not set or is the empty string.
Common situations: Running a capsule/hook binary manually outside the host (which normally injects the token); shell environments that strip the variable; launching the hook from cron/systemd without inheriting the parent environment.
Understand the failure class
Background: "environment variable is not set" and "Missing keys in environment" errors: what missing required env var messages mean and how to fix them — this error's family across 28 libraries.
Related errors
- Failed to resolve ASTRID_HOME for token path
- ASTRID_WORKSPACE_STATE_DIR must be valid UTF-8
- cannot load capsule ' ' for unadmitted principal
- could not authenticate as principal
- must be exactly 'file' or 'stderr', got
AI-assisted analysis of astrid-runtime/astrid@affd8760f4 (2026-09-09).
Data as JSON: /api/errors/afb6b2257c3eea8c.
Report an issue: GitHub.
Appendix: source
Thrown at crates/astrid-emit/src/lib.rs:353
})
}
/// Process-environment lookup: a variable counts as present only if it is
/// set **and** non-empty.
fn env_lookup(name: &str) -> Option<String> {
std::env::var(name).ok().filter(|v| !v.is_empty())
}
/// Read the hook token supplied by the host runner.
///
/// The runner mints and persists this token once per session. Hook events only
/// echo it; this helper deliberately never generates a replacement token.
///
/// # Errors
/// Returns an error when `ASTRID_HOOK_TOKEN` is missing or empty.
pub fn hook_token_from_env() -> Result<String> {
env_lookup("ASTRID_HOOK_TOKEN").ok_or_else(|| {
anyhow::anyhow!("required environment variable ASTRID_HOOK_TOKEN is missing or empty")
})
}
/// Core, testable logic: given a topic, stdin payload, the three env
/// values, and an [`Emitter`], build the envelope and publish it.
///
/// The caller (`run`) is responsible for writing the
/// `{"continue":true}` stdout line on **every** path — this function
/// only decides stderr + exit code. It never returns an exit code other
/// than `0` or `1`.
pub async fn emit<E: Emitter>(
emitter: &E,
topic: &str,
stdin_payload: &str,
env: &HookEnvValues<'_>,
) -> Outcome {
let hook = derive_hook(topic);
let envelope = build_envelope(View on GitHub (pinned to affd8760f4)