alibaba/nacos · error · Error

agentCard must be a JSON object

Error message

agentCard must be a JSON object

What it means

Thrown by normalizeA2aAgentCard after parsing the agentCard JSON text: the parsed value is not a plain object (it is an array, primitive, or null). The AgentCard must be a top-level JSON object so its fields (name, version, supportedInterfaces) can be read.

Source

Thrown at console-ui-next/src/pages/newAgent/agent-console-model.ts:234

    'AgentCard interface protocolVersion',
  );
  return {
    ...value,
    url,
    transport: protocolBinding,
    protocolBinding,
    protocolVersion,
  };
}

function normalizeA2aAgentCard(
  agentName: string,
  version: string,
  text: string,
): { card: Record<string, unknown>; declaredEndpoints: AgentCallInterface['declaredEndpoints'] } {
  const parsed = parseAgentCardJson(required(text, 'agentCard'));
  if (!isObject(parsed)) {
    throw new Error('agentCard must be a JSON object');
  }
  const card: Record<string, unknown> = { ...parsed, name: agentName, version };
  const topProtocolVersion = optionalString(card.protocolVersion);
  const preferredTransport = optionalString(card.preferredTransport);
  let interfaces: Record<string, unknown>[];
  if (Array.isArray(card.supportedInterfaces) && card.supportedInterfaces.length > 0) {
    interfaces = card.supportedInterfaces.map((item) => normalizeA2aInterface(
      item,
      preferredTransport,
      topProtocolVersion,
    ));
  } else {
    const preferred = normalizeA2aInterface({
      url: card.url,
      protocolBinding: preferredTransport,
      protocolVersion: topProtocolVersion,
    });
    interfaces = [preferred];

View on GitHub (pinned to 9b989acdf1)

Solutions

  1. Provide a full AgentCard object with top-level fields, not an array.
  2. Wrap a bare array in an object: {"supportedInterfaces":[...],"name":"...","version":"..."}.
  3. Validate the root type is an object before submit.

Example fix

// before
[{"url":"https://a.example.com","transport":"GRPC"}]

// after
{"name":"my-agent","version":"1.0.0","supportedInterfaces":[{"url":"https://a.example.com","transport":"GRPC"}]}
Defensive patterns

Strategy: type-guard

Validate before calling

function checkAgentCard(parsed) { if (parsed === null || Array.isArray(parsed) || typeof parsed !== 'object') throw new Error('agentCard must be an object'); }

Type guard

function isAgentCardObject(v: unknown): v is Record<string, unknown> {
  return v !== null && !Array.isArray(v) && typeof v === 'object';
}

Try / catch

try { normalizeA2aAgentCard(name, ver, text); } catch (e) {
  if (/agentCard must be a JSON object/.test(e.message)) { toast.error('Wrap the card in a JSON object'); }
}

Prevention

When it happens

Trigger: User enters a JSON array '[...]' or a bare string/number as the agentCard, or 'null'. parseAgentCardJson succeeds but the result is non-object.

Common situations: User wraps the card in an array by mistake. User pastes only the supportedInterfaces array thinking it is the whole card.

Related errors


AI-assisted analysis of alibaba/nacos@9b989acdf1 (2026-08-14). Data as JSON: /api/errors/51d82e00ffb36694. Report an issue: GitHub.