{"record":{"id":"946b3fa78dd0dc91","repo":"google-gemini/gemini-cli","slug":"remotesubagentprotocol-a2aclientmanager-not-avail","errorCode":null,"errorMessage":"RemoteSubagentProtocol: A2AClientManager not available for '${this.definition.name}'.","messagePattern":"RemoteSubagentProtocol: A2AClientManager not available for '(.+?)'\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"critical","filePath":"packages/core/src/agents/remote-subagent-protocol.ts","lineNumber":206,"sourceCode":"        // Abort resolves with an empty result — partial output is intentionally\n        // dropped since the caller requested cancellation.\n        this._resultResolve({\n          llmContent: [{ text: '' }],\n          returnDisplay: '',\n        });\n      } else {\n        this._emitErrorAndAgentEnd(err);\n        this._resultReject(err);\n      }\n    } finally {\n      this._clearActiveStream();\n    }\n  }\n\n  private async _runStream(query: string): Promise<void> {\n    const clientManager = this.context.config.getA2AClientManager();\n    if (!clientManager) {\n      throw new Error(\n        `RemoteSubagentProtocol: A2AClientManager not available for '${this.definition.name}'.`,\n      );\n    }\n\n    const authHandler = await this._getAuthHandler();\n    if (!clientManager.getClient(this.definition.name)) {\n      await clientManager.loadAgent(\n        this.definition.name,\n        getAgentCardLoadOptions(this.definition),\n        authHandler,\n      );\n    }\n\n    const reassembler = new A2AResultReassembler();\n    let prevText = '';\n\n    const stream = clientManager.sendMessageStream(\n      this.definition.name,","sourceCodeStart":188,"sourceCodeEnd":224,"githubUrl":"https://github.com/google-gemini/gemini-cli/blob/5024443c7217464a66e98f80d73172a26440bd8f/packages/core/src/agents/remote-subagent-protocol.ts#L188-L224","documentation":"Thrown inside RemoteSubagentProtocol._runStream() when config.getA2AClientManager() is undefined at the moment a streaming session starts. Unlike error 220 (which is a construction-time guard in RemoteSessionInvocation), this fires at execution time inside the protocol layer that wraps A2A client streaming behind the AgentProtocol interface. It means the config lost or never had its A2A client manager between session setup and stream start.","triggerScenarios":"Calling send() or startStream() on a RemoteSubagentProtocol instance whose context.config.getA2AClientManager() now returns undefined. This can occur if the config object was mutated or garbage-collected between protocol construction and stream execution, or if the protocol was constructed with a different (incomplete) config context than expected.","commonSituations":"Long-lived protocol objects whose underlying Config reference became stale after a hot-reload or reconfiguration; race conditions where the A2A subsystem is torn down (e.g., during shutdown) while an in-flight stream request arrives; test setups that construct the protocol with a mock config but forget to mock getA2AClientManager on the streaming path.","solutions":["Confirm the Config instance backing the AgentLoopContext has a populated a2aClientManager at call time, not just at construction time.","Avoid mutating or replacing the Config object after protocols have been created from it; rebuild protocols if reconfiguring.","In tests, mock config.getA2AClientManager to return a valid client manager for both construction and streaming code paths.","Guard the caller of _runStream with a pre-check: if (!ctx.config.getA2AClientManager()) return an error result to the user instead of throwing."],"exampleFix":"// before\nprivate async _runStream(query: string): Promise<void> {\n  const clientManager = this.context.config.getA2AClientManager();\n  if (!clientManager) {\n    throw new Error(`RemoteSubagentProtocol: A2AClientManager not available...`);\n  }\n  // ...\n}\n\n// after — surface a recoverable error to the caller\nprivate async _runStream(query: string): Promise<void> {\n  const clientManager = this.context.config.getA2AClientManager();\n  if (!clientManager) {\n    this._emitErrorAndAgentEnd(new Error(`A2AClientManager not available for '${this.definition.name}'. Initialize remote agents first.`));\n    return;\n  }\n  // ...\n}","handlingStrategy":"validation","validationCode":"// Before starting the stream, verify the manager is still present\nconst clientManager = this.context.config.getA2AClientManager();\nif (!clientManager) {\n  this._emitErrorAndAgentEnd(\n    new Error(`A2AClientManager unavailable for '${this.definition.name}'. Retry after init.`)\n  );\n  return;\n}","typeGuard":null,"tryCatchPattern":"try {\n  await protocol.send(query);\n} catch (e) {\n  if (e instanceof Error && e.message.includes('A2AClientManager not available')) {\n    // The A2A subsystem may have been torn down; reinitialize or report\n    return { error: 'Remote agent transport unavailable. Restart the session.' };\n  }\n  throw e;\n}","preventionTips":["Do not tear down or replace the Config object while protocol sessions are active.","Add a lifecycle check before stream start and emit a recoverable error event instead of throwing.","In integration tests, keep the mock client manager alive for the full session duration.","Log when a2aClientManager transitions to undefined to catch premature teardown."],"tags":["a2a","remote-agents","streaming","lifecycle"],"backgroundTag":null,"analyzedSha":"5024443c7217464a66e98f80d73172a26440bd8f","analyzedAt":"2026-08-12T06:01:53.711Z","schemaVersion":2},"datasetVersion":"2026-08-12T13:17:24.610Z"}