mastra-ai/mastra · error

Failed to canonicalize A2A Agent Card for signing

Error message

Failed to canonicalize A2A Agent Card for signing

What it means

signAgentCard() serializes the agent card deterministically using the canonicalize() (RFC 8785 JSON canonicalization) library after stripping existing signatures. If canonicalize returns a falsy value — which happens for input that is not valid canonicalizable JSON (e.g. undefined/invalid values, non-JSON-safe data like undefined fields, NaN, or a non-object) — the function throws this error rather than signing non-canonical data.

Source

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

function getDigestAlgorithm(algorithm: string): string {
  if (algorithm.endsWith('256')) return 'sha256';
  if (algorithm.endsWith('384')) return 'sha384';
  if (algorithm.endsWith('512')) return 'sha512';
  throw new Error(`Unsupported JWS algorithm for A2A Agent Card signing: ${algorithm}`);
}

export async function signAgentCard({
  agentCard,
  signing,
}: {
  agentCard: AgentCard;
  signing: A2AAgentCardSigningConfig;
}): Promise<AgentCard> {
  const canonicalPayload = canonicalize(stripAgentCardSignatures(agentCard));

  if (!canonicalPayload) {
    throw new Error('Failed to canonicalize A2A Agent Card for signing');
  }

  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) {

View on GitHub (pinned to 75dd419e61)

Solutions

  1. Log/inspect the agent card passed to signAgentCard and remove non-JSON-safe values (undefined, bigint, NaN, functions).
  2. Ensure the card is a plain JSON object — deep-clone through JSON.parse(JSON.stringify(card)) before signing if needed.
  3. Verify the card is fully populated (not undefined) before calling signAgentCard.
  4. Check the canonicalize dependency is correctly installed/Functioning (a broken import could yield a non-function whose result is falsy).

Example fix

// before
await signAgentCard({ agentCard: maybeUndefinedCard, signing });
// after
if (!agentCard || typeof agentCard !== 'object') throw new Error('Agent card missing');
const safeCard = JSON.parse(JSON.stringify(agentCard));
await signAgentCard({ agentCard: safeCard, signing });
Defensive patterns

Strategy: validation

Validate before calling

function isJsonSafe(v: unknown, seen = new Set()): boolean {
  if (v === null || ['string','number','boolean'].includes(typeof v)) return true;
  if (typeof v !== 'object' || seen.has(v)) return false;
  seen.add(v);
  return Object.values(v).every(x => isJsonSafe(x, seen));
}
// require isJsonSafe(agentCard) before signAgentCard

Type guard

const isAgentCardObject = (c: unknown): c is Record<string, unknown> =>
  typeof c === 'object' && c !== null && !Array.isArray(c);

Try / catch

let signedCard;
try {
  signedCard = await signAgentCard({ agentCard, signing });
} catch (e) {
  if (e.message.includes('Failed to canonicalize')) {
    const safe = JSON.parse(JSON.stringify(agentCard));
    signedCard = await signAgentCard({ agentCard: safe, signing });
  } else throw e;
}

Prevention

When it happens

Trigger: Calling signAgentCard with an AgentCard whose serialized form is not RFC 8785 canonicalizable — e.g. the card is undefined/null at runtime, or contains values JSON can't represent deterministically.

Common situations: Agent card constructed at runtime with undefined fields (bigints, undefined, functions in values); a storage/registry layer returning an empty or malformed card; version drift where the AgentCard type gained non-JSON-safe fields.

Related errors


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