Hmbown/CodeWhale · error

Managing API keys needs an interactive login. Run…

Error message

Managing API keys needs an interactive login. Run `codewhale login`.
{MACHINE_KEY_ENV} is set, but a Codewhale API key deliberately cannot create, list, or revoke keys — that is what stops a leaked key from minting a replacement for itself.

What it means

reject_machine_key_for_management enforces a security invariant: a machine API key (MACHINE_KEY_ENV) can authenticate API calls but can never create, list, or revoke keys. Key management requires an interactive session login; when a machine key is present and no session exists, the CLI bails and states the rationale — preventing a leaked key from minting its own replacement.

Solutions

  1. Run `codewhale login` in an interactive terminal to establish a session, then retry the management command
  2. Unset the machine key env var if it is not needed for this command: `unset $MACHINE_KEY_ENV`
  3. Perform key management from a machine with an interactive session, not from CI
  4. Use the web console/dashboard to manage keys if CLI login is impossible
Defensive patterns

Strategy: fallback

Validate before calling

// shell: require a session before management commands
if [ -n "$MACHINE_KEY_ENV_VALUE" ] && ! codewhale whoami >/dev/null 2>&1; then
  echo "run 'codewhale login' for key management"; exit 1
fi

Prevention

When it happens

Trigger: Running any api-keys management subcommand (create/list/revoke) while MACHINE_KEY_ENV is set and there is no interactive login session, i.e. has_session is false and machine.is_present() is true (crates/cli/src/cloud/machine.rs:875).

Common situations: CI or scripted environments where only the machine key env var is set and someone tries to rotate keys non-interactively; a developer who logged out but still has the env var exported; Docker containers with the key injected as an env var.

Related errors


AI-assisted analysis of Hmbown/CodeWhale@73e0f67d83 (2026-09-22). Data as JSON: /api/errors/55b2af459dde9b08. Report an issue: GitHub.

Appendix: source

Thrown at crates/cli/src/cloud/machine.rs:875

in the display prefix. Run `codewhale account api-keys list` to see them."
        );
    }
    Ok(id)
}

/// Refuse a management command that would be authenticated by a machine key.
///
/// The server would answer 403 `api_key_route_denied`, but a local refusal is
/// better: it never puts the credential on the wire, and it names the fix.
/// This is the load-bearing rule of the whole design — a stolen key must not
/// be able to bootstrap a successor that outlives the revocation of the key
/// that was stolen — so the CLI states it rather than discovering it.
pub(crate) fn reject_machine_key_for_management(
    machine: &MachineKeyEnv,
    has_session: bool,
) -> Result<()> {
    if machine.is_present() && !has_session {
        bail!(
            "Managing API keys needs an interactive login. Run `codewhale login`.\n\
{MACHINE_KEY_ENV} is set, but a Codewhale API key deliberately cannot create, list, or \
revoke keys — that is what stops a leaked key from minting a replacement for itself."
        );
    }
    Ok(())
}

/// Run `codewhale account api-keys …` against the interactive session.
pub(crate) fn run_api_keys<T: CloudTransport, W: Write>(
    args: ApiKeysArgs,
    client: &CloudClient<'_, T>,
    machine: &MachineKeyEnv,
    provider_secrets: &codewhale_secrets::Secrets,
    out: &mut W,
    sleeper: &mut dyn FnMut(Duration),
) -> Result<()> {
    reject_machine_key_for_management(machine, client.has_session()?)?;

View on GitHub (pinned to 73e0f67d83)