Skip to content

Tool call hangs after extension startup fails #4670

Description

@MattPD

Describe the bug

After I resumed a long-lived session, an extension failed during session.resume before it reported ready. The CLI continued to expose the extension's custom tool after the extension process exited.

The call never reached the handler and returned no error. It remained pending for 9 minutes 38 seconds until I aborted it.

The startup failure was:

Request session.resume failed with message: Invalid string length
peer-closed-before-ready
exit code=1 disposition=startup-failure

The tool's successful path would create a target file. No target appeared. The extension process had already exited, so the stale registration had no live handler.

Environment

GitHub Copilot CLI 1.0.82
Linux x86_64

Relevant extension shape

The affected extension registered a custom tool through joinSession(). This reduced example shows the same lifecycle shape.

import { writeFile } from "node:fs/promises";
import { joinSession } from "@github/copilot-sdk/extension";

await joinSession({
    tools: [
        {
            name: "stale_tool_probe",
            description: "Verify extension tool lifecycle.",
            parameters: {
                type: "object",
                properties: {},
                additionalProperties: false,
            },
            skipPermission: true,
            handler: async () => {
                await writeFile(
                    new URL("handler-ran.marker", import.meta.url),
                    "handler ran\n",
                );
                return "handler-ran";
            },
        },
    ],
});

Steps from the failing run

  1. I stored the extension under ~/.copilot/session-state/<session-id>/extensions/stale-tool-probe/extension.mjs.
  2. I resumed the session.
  3. The extension produced the quoted startup failure and exited before reporting ready.
  4. I asked the agent to invoke stale_tool_probe.
  5. The CLI still offered the tool, and the call remained pending instead of returning an error about the exited extension.

The trigger may depend on session size or resume history. The failing session's events.jsonl file was about 1.2 GB. I do not yet have a smaller deterministic reproducer.

A separate hook-and-tool extension using the same SDK joined a fresh small session, handled tool calls, and survived resume. Extensions and joinSession() therefore work generally on this host.

Expected behavior

  • The CLI exposes a tool registration only after its owning extension reports ready.
  • A startup failure removes every provisional registration owned by that process.
  • A call to a tool whose extension has exited fails promptly and names that extension.
  • Reloading extensions removes registrations whose owning process has exited.
  • The CLI reports the session.resume failure and any later stale-tool call as separate errors.

Actual behavior

  • The extension failed before ready and exited.
  • Its tool stayed visible.
  • The stale call never reached the handler.
  • The stale call returned no error within 9 minutes 38 seconds.
  • I recovered only by aborting the call.

Additional context

I inspected the published SDK's joinSession() implementation. Its session.resume request contains extension registration options rather than session history. A successful response contains workspace, capability, and canvas metadata.

The large session file correlates with the failure, but the evidence does not establish it as the cause. The failure appears in the runtime's session resume or extension attachment path, but I have not isolated the component.

Potentially related issues

Issue 4590 reports a different session.resume failure and hook-processor disposal during extension reconnects.

Issue 3856 reports extension tools disappearing when a resume operation creates separate contexts.

The current report covers the opposite tool lifecycle outcome: The CLI keeps a tool callable after its extension fails before reporting ready.

Metadata

Metadata

Assignees

No one assigned

    Labels

    area:pluginsPlugin system, marketplace, hooks, skills, extensions, and custom agentsarea:sessionsSession management, resume, history, session picker, and session statearea:toolsBuilt-in tools: file editing, shell, search, LSP, git, and tool call behavior

    Type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions