mastra-ai/mastra · error · MastraClientError

A2A Agent Card signature verification failed: ${verification

Error message

A2A Agent Card signature verification failed: ${verificationErrors.join('; ')}

What it means

This is the aggregate error thrown when every signature on the Agent Card failed verification. Each per-signature failure (missing alg, disallowed alg, missing key, import failure, or compactVerify signature mismatch) is collected into verificationErrors and joined with '; '. If any single signature had verified, the card would have been returned early — reaching here means none did.

Source

Thrown at client-sdks/client-js/src/utils/verify-agent-card-signature.ts:147

        index,
      });

      if (!verificationKey) {
        throw new Error('No verification key was provided for Agent Card signature verification');
      }

      const importedKey = await importVerificationKey(verificationKey, protectedHeader.alg);
      await compactVerify(compactJws, importedKey, {
        algorithms: allowedAlgorithms,
      });

      return agentCard;
    } catch (error) {
      verificationErrors.push(error instanceof Error ? error.message : 'Unknown verification failure');
    }
  }

  throw new MastraClientError(
    200,
    'OK',
    `A2A Agent Card signature verification failed: ${verificationErrors.join('; ')}`,
  );
}

View on GitHub (pinned to 75dd419e61)

Solutions

  1. Read the joined sub-errors in the message to identify the concrete per-signature cause (missing key vs disallowed alg vs crypto mismatch).
  2. Confirm the public key returned by your keyProvider is the exact pair of the server's signing private key.
  3. Ensure the server signs the card and does not modify it afterwards — the signature covers canonicalize(card minus signatures).
  4. Align @mastra/core (server signer) and client-js versions so canonicalization and defaults match.
  5. As a diagnostic, verify the detached JWS manually with jose against the canonicalized card to isolate the failing component.

Example fix

// before: stale public key after server rotation
const client = new MastraClient({ baseUrl, verifyAgentCardSignature: { keyProvider: () => oldPem } });

// after: resolve the current key by kid
const client = new MastraClient({ baseUrl, verifyAgentCardSignature: { keyProvider: async ({ kid }) => await jwks.getByKid(kid) } });
Defensive patterns

Strategy: try-catch

Validate before calling

// pre-flight: check at least one signature looks verifiable before trusting the card
if (card.signatures?.length && !keyStoreCoversKids(card.signatures.map(s => decodeHeader(s.protected).kid))) {
  console.warn('Agent Card signatures cannot be verified with current keys');
}

Type guard

function isMastraClientError(e: unknown): e is MastraClientError {
  return e instanceof MastraClientError;
}

Try / catch

let agentCard;
try {
  agentCard = await client.getAgentCard();
} catch (e) {
  if (e instanceof MastraClientError && e.message.startsWith('A2A Agent Card signature verification failed')) {
    // inspect e.message sub-errors; decide: fail closed (rethrow) or fetch unsigned card
    throw e;
  }
  throw e;
}

Prevention

When it happens

Trigger: getAgentCard() with verification enabled where the card carries signatures but compactVerify fails for all of them — typically the canonical payload doesn't match what was signed, the key is wrong (different key than the signer's private counterpart), or every signature hits one of the per-signature errors (215-218 family).

Common situations: Server mutates the card after signing (adding fields) so the payload no longer matches; verifier holds the wrong public key or a certificate for a different issuer; the server and client canonicalize differently (version mismatch); clock/key rotation races after a deploy.

Related errors


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