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

  1. Run the hook through the normal astrid host launch path so it injects `ASTRID_HOOK_TOKEN`.
  2. If manual invocation is required, copy the token value the host exposed into the environment: `ASTRID_HOOK_TOKEN=<token> <command>`.
  3. 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

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


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)