Hmbown/CodeWhale · error · Error
invalid base64
Error message
invalid base64
What it means
strictBase64 validates a string as canonical standard base64 before decoding: non-empty, length multiple of 4, only A-Za-z0-9+/ with up to two trailing '=', and length within the bound implied by maxBytes. The first throw happens when the input fails these format checks — this bounds allocation and rejects ambiguous encodings before Buffer decoding.
Solutions
- Convert base64url to standard base64: replace '-'→'+' and '_'→'/', pad with '=' to a multiple of 4
- Strip whitespace and any scheme prefix from the value
- Check that the string length is a multiple of 4 and the charset matches /^[A-Za-z0-9+/]*={0,2}$/
Example fix
// before
strictBase64('a-b_c=', 32); // base64url chars
// after
const std = ('a-b_c='.replace(/-/g, '+').replace(/_/g, '/') + '==').slice(0, Math.ceil('a-b_c='.length / 4) * 4);
strictBase64(std, 32); Defensive patterns
Strategy: validation
Validate before calling
const looksLikeBase64 = (s) => typeof s === 'string' && s.length > 0 && s.length % 4 === 0 && /^[A-Za-z0-9+/]*={0,2}$/.test(s);
if (!looksLikeBase64(value)) throw new Error('not canonical base64'); Type guard
const isCanonicalB64Shape = (v) => typeof v === 'string' && v.length > 0 && v.length % 4 === 0 && /^[A-Za-z0-9+/]*={0,2}$/.test(v); Try / catch
try { key = strictBase64(value, 32); } catch (e) { if (e.message === 'invalid base64') { value = normalizeToStdBase64(value); key = strictBase64(value, 32); } else throw e; } Prevention
- Convert base64url (JWT segments) to standard base64 before use
- Strip whitespace/line-wrapping from copied keys
- Ensure length is a multiple of 4 with correct padding
When it happens
Trigger: Passing a value that is not a string, an empty string, a string containing '-'/'_' (base64url alphabet), whitespace/newlines, or a length that is not a multiple of 4.
Common situations: Pasting URL-safe base64 (JWT segments) where standard base64 is required, copying a key with line breaks or a 'base64:' prefix, or passing undefined/null.
Understand the failure class
Background: "Invalid ... format", "must be in format X", "does not look like a ..." — invalid argument format errors across CLI tools and libraries — this error's family across 17 libraries.
Related errors
- invalid-base64
- image base64 is not canonical
- image has invalid base64
- invalid tool image evidence
- operation_key cannot contain control characters
AI-assisted analysis of Hmbown/CodeWhale@433685b202 (2026-09-15).
Data as JSON: /api/errors/a1d9fa6d5d3ee5c2.
Report an issue: GitHub.
Appendix: source
Thrown at web/scripts/facts-publish.mjs:90
// Ed25519 SPKI DER is a fixed 12-byte prefix followed by the 32-byte key.
return spki.subarray(spki.length - 32);
}
export function publicKeyObjectFromRaw(rawB64) {
const raw = strictBase64(rawB64, 32);
if (raw.length !== 32) throw new Error("public key must decode to 32 bytes");
const prefix = Buffer.from("302a300506032b6570032100", "hex");
return createPublicKey({ key: Buffer.concat([prefix, raw]), type: "spki", format: "der" });
}
export function signPayload(privateKey, keyId, payloadBytes) {
return sign(null, signingMessage(keyId, payloadBytes), privateKey);
}
/** Canonical base64 is checked before decoding to bound allocation. */
export function strictBase64(value, maxBytes) {
if (typeof value !== "string" || !value.length || value.length > 4 * Math.ceil(maxBytes / 3) ||
(value.length % 4 !== 0 || !/^[A-Za-z0-9+/]*={0,2}$/.test(value))) throw new Error("invalid base64");
const bytes = Buffer.from(value, "base64");
if (bytes.length > maxBytes || bytes.toString("base64") !== value) throw new Error("invalid base64");
return bytes;
}
export function utcTime(value) {
if (typeof value !== "string" || !/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d{1,3})?Z$/.test(value)) return null;
const time = Date.parse(value);
return Number.isFinite(time) && new Date(time).toISOString().slice(0, 19) === value.slice(0, 19) ? time : null;
}
export function verifyEnvelope(envelope, publicKeyB64) {
const errors = [];
if (!isPlainObject(envelope)) return { ok: false, errors: ["envelope must be an object"] };
if (envelope.envelope !== ENVELOPE_VERSION) errors.push("unsupported envelope version");
if (envelope.alg !== "ed25519") errors.push("unsupported signature algorithm");
if (typeof envelope.key_id !== "string" || !KEY_ID_RE.test(envelope.key_id)) errors.push("bad key_id");
if (envelope.schema_version !== SCHEMA_VERSION) errors.push("unsupported schema version");View on GitHub (pinned to 433685b202)