Hmbown/CodeWhale · critical · Error

self-verify failed

Error message

self-verify failed: ${check.errors.join("; ")}

What it means

After constructing the envelope, buildEnvelope immediately verifies it against the derived public key via verifyEnvelope. If that self-verification fails, this error aggregates the verifier's error list. It is an internal safety net: a produced envelope that cannot be verified is never returned to the caller.

Solutions

  1. Read the joined check.errors in the message to see which verification rule failed
  2. Regenerate or re-export the signing key and confirm createPrivateKey yields an Ed25519 key
  3. Sign a trivial payload to isolate whether the problem is the key or the payload fields
  4. If you modified this script, diff buildEnvelope and verifyEnvelope against git HEAD

Example fix

// before
const key = createPrivateKey(fs.readFileSync(process.env.KEY_PATH));
await buildEnvelope({ privateKey: key, keyId, payload });
// after
const key = createPrivateKey({ key: fs.readFileSync(process.env.KEY_PATH), format: 'pem' });
if (key.asymmetricKeyType !== 'ed25519') throw new Error('need Ed25519 key');
await buildEnvelope({ privateKey: key, keyId, payload });
Defensive patterns

Strategy: try-catch

Validate before calling

const key = createPrivateKey({ key: pem, format: 'pem' });
if (key.asymmetricKeyType !== 'ed25519') throw new Error('signing key must be Ed25519 before envelope build');

Type guard

const isEd25519Private = (k) => { try { return createPrivateKey(k).asymmetricKeyType === 'ed25519'; } catch { return false; } };

Try / catch

try { env = buildEnvelope({ privateKey, keyId, payload }); } catch (e) { if (e.message.startsWith('self-verify failed')) { console.error('Envelope failed self-verify:', e.message); process.exit(3); } throw e; }

Prevention

When it happens

Trigger: buildEnvelope produced an envelope that verifyEnvelope rejects — e.g. signature mismatch (wrong/unsupported private key), a payload field the verifier considers invalid, or the not_after/version fields breaking verification invariants.

Common situations: Passing a corrupted or wrong-format private key whose derived public key does not match the signature; tampered buildEnvelope/verifyEnvelope code after local edits; key object that is not a usable Ed25519 private key despite parsing.

Related errors


AI-assisted analysis of Hmbown/CodeWhale@433685b202 (2026-09-15). Data as JSON: /api/errors/8ef5a378117d57b4. Report an issue: GitHub.

Appendix: source

Thrown at web/scripts/facts-publish.mjs:318

  const sha256 = createHash("sha256").update(payloadBytes).digest("hex");
  const envelope = {
    envelope: ENVELOPE_VERSION,
    channel: payload.channel,
    facts_version: payload.facts_version,
    schema_version: payload.schema_version,
    key_id: keyId,
    alg: "ed25519",
    applies_to: payload.applies_to,
    published_at: payload.published_at,
    payload_b64: payloadBytes.toString("base64"),
    sig_b64: sig.toString("base64"),
    sigs: [],
    sha256,
  };
  if (payload.not_after != null) envelope.not_after = payload.not_after;
  const pub = rawPublicKeyFromKeyObject(createPublicKey(privateKey)).toString("base64");
  const check = verifyEnvelope(envelope, pub);
  if (!check.ok) throw new Error(`self-verify failed: ${check.errors.join("; ")}`);
  return envelope;
}

// ---------------------------------------------------------------------------
// CLI helpers
// ---------------------------------------------------------------------------

function parseArgs(argv) {
  const positional = [];
  const flags = {};
  for (let i = 0; i < argv.length; i += 1) {
    const arg = argv[i];
    if (arg.startsWith("--")) {
      const key = arg.slice(2);
      const next = argv[i + 1];
      if (next === undefined || next.startsWith("--")) flags[key] = true;
      else { flags[key] = next; i += 1; }
    } else positional.push(arg);

View on GitHub (pinned to 433685b202)