mastra-ai/mastra · error

Failed to create compact JWS for A2A Agent Card

Error message

Failed to create compact JWS for A2A Agent Card

What it means

After producing the compact JWS pieces, signAgentCard() validates that both the base64url-encoded protected header and the signature buffer are non-empty before assembling the AgentCardSignature. If either is empty — indicating the signing operation silently produced no output — it throws this error instead of attaching an invalid/empty signature to the agent card.

Source

Thrown at packages/server/src/server/a2a/agent-card-signing.ts:103

  }

  const key = importSigningKey(signing);
  const protectedHeader = getProtectedHeader(signing);
  const encodedHeader = Buffer.from(JSON.stringify(protectedHeader), 'utf8').toString('base64url');
  const encodedPayload = Buffer.from(canonicalPayload, 'utf8').toString('base64url');
  const signingInput = `${encodedHeader}.${encodedPayload}`;
  const signatureBuffer = crypto.sign(
    getDigestAlgorithm(String(protectedHeader.alg)),
    Buffer.from(signingInput, 'utf8'),
    {
      key,
      ...getSignatureOptions(String(protectedHeader.alg)),
    },
  );
  const signatureValue = signatureBuffer.toString('base64url');

  if (!encodedHeader || !signatureValue) {
    throw new Error('Failed to create compact JWS for A2A Agent Card');
  }

  const signature: AgentCardSignature = {
    protected: encodedHeader,
    signature: signatureValue,
    header: signing.header,
  };

  return {
    ...agentCard,
    signatures: [...(agentCard.signatures ?? []), signature],
  };
}

View on GitHub (pinned to 75dd419e61)

Solutions

  1. Verify the private key material (PEM or JWK) is valid and non-empty; test with crypto.createPrivateKey locally.
  2. Confirm the key type matches the alg (EC key for ES256, RSA for RS/PS).
  3. Check that no build/bundling step stripped or zeroed the key (e.g. env var not injected at deploy time).
  4. Log encodedHeader and the raw signature buffer before this point to isolate which piece is empty.

Example fix

// before
signing: { privateKey: process.env.EMPTY_KEY as any, protectedHeader: { alg: 'ES256' } }
// after
const pem = process.env.A2A_SIGNING_KEY; // ensure populated, valid PEM
if (!pem) throw new Error('A2A_SIGNING_KEY not configured');
signing: { privateKey: pem, protectedHeader: { alg: 'ES256' } }
Defensive patterns

Strategy: validation

Validate before calling

import crypto from 'node:crypto';
// pre-flight: ensure the key imports and can sign
const key = typeof pem === 'string' ? crypto.createPrivateKey(pem) : crypto.createPrivateKey({ key: pem, format: 'jwk' });
crypto.sign('sha256', Buffer.from('test'), key); // throws early on bad key

Type guard

const isNonEmptyString = (s: unknown): s is string => typeof s === 'string' && s.length > 0;

Try / catch

try {
  signedCard = await signAgentCard({ agentCard, signing });
} catch (e) {
  if (e.message.includes('Failed to create compact JWS')) {
    throw new Error('Signing key produced empty output — verify A2A signing key material and alg');
  }
  throw e;
}

Prevention

When it happens

Trigger: The crypto sign operation returns an empty buffer or the encoded header is empty — typically a defective/zero-length signing key, an importSigningKey edge case, or a crypto backend failure that resolves without throwing.

Common situations: A private key imported from a malformed JWK or PEM that produces empty output; key/cert mismatched or zero-length key material in env config; unusual Node crypto backends (FIPS) altering behavior.

Related errors


AI-assisted analysis of mastra-ai/mastra@75dd419e61 (2026-08-30). Data as JSON: /api/errors/6174a697deb1734e. Report an issue: GitHub.