google-gemini / google-gemini/gemini-cli

bug(a2a-server): fire-and-forget scheduler.schedule() rejection can crash the whole server process

Open Beginner friendly
#29,034 0 comments 0 reactions 0 assignees View on GitHub
area/agent status/need-triage
Dominant language
TypeScript
Stars
107k
Forks
14.6k
Avg merge
2d 3h
Merged PRs (30d)
45

Description

## What happened?

The A2A server schedules tool batches with a deliberately fire-and-forget promise:

```ts
// Fire and forget so we don't block the executor loop before waitForPendingTools can be called
void this.scheduler.schedule(updatedRequests, abortSignal);
```

But `CoreToolScheduler.schedule()` **legitimately rejects**: `_enqueueRequest()` rejects with `'Tool call cancelled while in queue.'` when the signal aborts while queued, and with `'Operation cancelled'` if already aborted (`packages/core/src/scheduler/scheduler.ts:229-243`). Discarding the promise with `void` turns those rejections into **unhandled rejections**, which under Node's default mode (`--unhandled-rejections=throw`, default since Node 15) terminate the entire a2a-server process — taking down every other running task.

## Affected code

`packages/a2a-server/src/agent/task.ts:817-818`:

```ts
void this.scheduler.schedule(updatedRequests, abortSignal);
```

## How can this be reproduced?

1. Start a task that runs two sequential tool batches.
2. While batch 2 is queued behind batch 1, abort the task (client cancel / socket close triggers `abortController.abort()` in executor.ts).
3. If batch 2 was enqueued before the abort raced the dequeue, `_enqueueRequest` rejects → unhandled rejection → server exits.

Note: PR #27686 codifies `void` as the idiomatic *lint* marker for intentional fire-and-forget, but does not add rejection handling; the hazard here is the un-handled rejection path itself, not the style.

## What did you expect to happen?

Cancellation should be swallowed explicitly (e.g., `.catch(err => { if (!isAbortError(err)) logger.error(err); })`) so aborting one task never kills unrelated tasks.

## Suggested direction

Attach a targeted `.catch()` that treats abort/cancel errors as expected and logs anything else.

---

*Found by source audit on current `main` (commit `5411f113c`); platform-independent. No open issue covering this crash path was found (searched: a2a unhandled rejection).*

Contributor guide

Open the contributing guide

Research direction

Start in packages/a2a-server/src/agent/task.ts:817-818, then inspect the rejection paths in packages/core/src/scheduler/scheduler.ts:229-243 and the abort flow in executor.ts. Verify that expected cancellation does not create an unhandled rejection or terminate the server, while unexpected scheduler errors are logged.

Written by the indexing model from the issue text.

Assessment

Tech stack
node.js, typescript
Domain
api, backend
Issue type
Bug
Difficulty
2/5
Estimated time
1-3 hours
Activity status
Active
Clarity
Clearly specified
Newbie friendliness
88/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.