google-gemini/gemini-cli · critical · AgentLoadError

Unexpected state: neither agent_card_json nor agent_card_url

Error message

Unexpected state: neither agent_card_json nor agent_card_url present on remote agent

What it means

markdownToAgentDefinition builds a RemoteAgentDefinition only after the frontmatter passed schema validation, so a remote agent is expected to carry either agent_card_json or agent_card_url. Reaching this throw means the schema accepted a remote-kind object without either field - an invariant violation indicating a gap between markdownFrontmatterSchema and this builder. The 'Unexpected state' wording marks it as a shouldn't-happen condition.

Source

Thrown at packages/core/src/agents/agentLoader.ts:540

        ? convertFrontmatterAuthToConfig(markdown.auth)
        : undefined,
      inputConfig,
      metadata,
    };

    if (
      'agent_card_json' in markdown &&
      markdown.agent_card_json !== undefined
    ) {
      base.agentCardJson = markdown.agent_card_json;
      return base;
    }
    if ('agent_card_url' in markdown && markdown.agent_card_url !== undefined) {
      base.agentCardUrl = markdown.agent_card_url;
      return base;
    }

    throw new AgentLoadError(
      metadata?.filePath || 'unknown',
      'Unexpected state: neither agent_card_json nor agent_card_url present on remote agent',
    );
  }

  // If a model is specified, use it. Otherwise, inherit
  const modelName = markdown.model || 'inherit';

  const mcpServers: Record<string, MCPServerConfig> = {};
  if (markdown.mcp_servers) {
    for (const [name, config] of Object.entries(markdown.mcp_servers)) {
      let authProviderType: AuthProviderType | undefined = undefined;
      let oauth: MCPOAuthConfig | undefined = undefined;

      if (config.auth) {
        if (config.auth.type === 'google-credentials') {
          authProviderType = AuthProviderType.GOOGLE_CREDENTIALS;
          oauth = {

View on GitHub (pinned to 5024443c72)

Solutions

  1. If authoring a file, add either agent_card_url or agent_card_json to the remote frontmatter.
  2. If this fires from a valid file, the schema is too permissive - tighten markdownFrontmatterSchema's remote branch to require one card field.
  3. If constructing the object in code, run it through parseAgentMarkdown/validate first.
  4. Report as a loader bug since the schema should have caught it earlier.

Example fix

# before
---
name: remote-svc
kind: remote
# no card field
---

# after
---
name: remote-svc
kind: remote
agent_card_url: https://svc.example/.well-known/agent-card.json
---
Defensive patterns

Strategy: validation

Validate before calling

function hasRemoteCardField(md: { kind?: string }): boolean {
  return 'agent_card_json' in md || 'agent_card_url' in md;
}
if (frontmatter.kind === 'remote' && !hasRemoteCardField(frontmatter)) {
  throw new Error('Remote agent requires agent_card_json or agent_card_url.');
}

Prevention

When it happens

Trigger: The schema union matched a remote branch that does not enforce agent_card_json/agent_card_url as required; a discriminator matched 'remote' via a different key; an extension to the schema added a remote variant without the card fields; the frontmatter was constructed programmatically and bypassed strict parsing.

Common situations: A schema refactor loosened the remote branch; a test constructed a FrontmatterAgentDefinition object directly without running the schema; a feature added a new remote kind without updating the builder's guard.

Related errors


AI-assisted analysis of google-gemini/gemini-cli@5024443c72 (2026-08-12). Data as JSON: /api/errors/2bb34cb0c2c7d29b. Report an issue: GitHub.