Hmbown/CodeWhale · error
is not a well-formed Codewhale API key, so it was not sent…
Error message
{MACHINE_KEY_ENV} is not a well-formed Codewhale API key, so it was not sent. Expected {TOKEN_LEN} characters shaped `cwc_key_<24 hex>_<43 chars>`; got {} characters. That is almost always a truncated or shell-mangled paste — re-copy the value, or create a new key with `codewhale account api-keys create`. What it means
MachineKeyEnv::parse validates the environment-provided Codewhale API key against the exact token shape `cwc_key_<24 hex>_<43 chars>` (TOKEN_LEN characters). A value that fails token_is_well_formed is refused locally and never sent, with a message showing the actual character count, because a malformed value is almost always a truncated or shell-mangled paste and a local diagnosis beats an ambiguous server 401.
Solutions
- Re-copy the full key from `codewhale account api-keys list` and re-export the env var
- Verify length and shape: `echo -n "$MACHINE_KEY_ENV" | wc -c` should equal TOKEN_LEN, and it should match `^cwc_key_[0-9a-f]{24}_[A-Za-z0-9]{43}$`
- Remove surrounding quotes if you pasted them from JSON/YAML: export the raw value
- Create a new key with `codewhale account api-keys create` if the original cannot be recovered
Example fix
// before export CODEWHALE_MACHINE_KEY="cwc_key_9f2a..." # truncated // after export CODEWHALE_MACHINE_KEY="cwc_key_a1b2c3d4e5f60718293a4b5c_x7Yz...(43 chars)"
Defensive patterns
Strategy: validation
Validate before calling
// shell check before exporting
if ! echo -n "$MACHINE_KEY_ENV" | grep -Eq '^cwc_key_[0-9a-f]{24}_[A-Za-z0-9]{43}$'; then
echo "machine key malformed"; exit 1
fi Type guard
fn is_well_formed_machine_key(raw: &str) -> bool {
let v = raw.trim().trim_matches('"');
v.len() == 24 + 1 + 43 + "cwc_key_".len()
&& v.starts_with("cwc_key_")
&& v[8..32].bytes().all(|b| b.is_ascii_hexdigit() && !b.is_ascii_uppercase())
} Prevention
- Copy machine keys whole from a trusted source; never retype them
- Validate the shape with a regex before exporting to the environment
- Keep the key in a single-line secret file and load it with trimming
- Rotate via `codewhale account api-keys create` rather than hand-editing old values
When it happens
Trigger: Setting MACHINE_KEY_ENV to a value that is not exactly TOKEN_LEN characters matching cwc_key_ + 24 hex + _ + 43 chars — truncated paste, quotes left in (unwrap_quoted strips one level), wrong variable exported, or a key from another provider (crates/cli/src/cloud/machine.rs:98, RAISED IN parse).
Common situations: Copy that stopped mid-key, a shell history entry with escaped/missing characters, wrapping quotes captured from JSON, editing the key in an editor that line-wrapped it, or exporting a placeholder like `cwc_key_...`.
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
- API key contains invalid control characters
- API key id must be lowercase hex characters — the part…
- API key must be - UTF-8 bytes
- API key name must be 1
- A positive pull request number is required
AI-assisted analysis of Hmbown/CodeWhale@73e0f67d83 (2026-09-22).
Data as JSON: /api/errors/decf6f3b07cb5930.
Report an issue: GitHub.
Appendix: source
Thrown at crates/cli/src/cloud/machine.rs:98
// ---------------------------------------------------------------------------
/// A validated machine token.
///
/// No `Display`, and `Debug` prints only the non-secret head, so the value
/// cannot reach a panic message or a `{:?}` dump by accident.
#[derive(Clone)]
pub(crate) struct MachineKey(String);
impl MachineKey {
/// Validate a raw environment value without sending it anywhere.
///
/// A malformed value is almost always a truncated or shell-mangled paste.
/// Saying so locally is strictly more useful than a server 401, which
/// cannot distinguish "you pasted half a key" from "this key was deleted".
pub(crate) fn parse(raw: &str) -> Result<Self> {
let value = unwrap_quoted(raw);
if !token_is_well_formed(value) {
bail!(
"{MACHINE_KEY_ENV} is not a well-formed Codewhale API key, so it was not sent. \
Expected {TOKEN_LEN} characters shaped `cwc_key_<24 hex>_<43 chars>`; got {} characters. \
That is almost always a truncated or shell-mangled paste — re-copy the value, or create a \
new key with `codewhale account api-keys create`.",
value.chars().count()
);
}
Ok(Self(value.to_string()))
}
/// The non-secret 32-character head: `cwc_key_` plus the 24-hex key id.
#[must_use]
pub(crate) fn head(&self) -> &str {
&self.0[..TOKEN_HEAD_LEN]
}
/// Hand the full token to the transport. The only caller is this module.
fn expose(&self) -> String {View on GitHub (pinned to 73e0f67d83)