CopilotKit / CopilotKit/CopilotKit
🐛 Bug: NodeFetchHandler hung
Open
Nobody has claimed this yet.
bug
- Dominant language
- TypeScript
- Stars
- 37.4k
- Forks
- 4.6k
- Avg merge
- 1d 6h
- Merged PRs (30d)
- 444
Description
♻️ Reproduction Steps
import { createControllerModule } from "@ai/apis/common/controller-module.factory";
import { V1Controller } from "@ai/apis/common/decorators";
import { jsonStringify } from "@ai/common/utils/json";
import { CopilotKitService } from "@ai/domains/copilot-kit/copilot-kit.interface";
import { CopilotKitModule } from "@ai/domains/copilot-kit/copilot-kit.module";
import {
BuiltInAgent,
CopilotKitIntelligence,
CopilotRuntime,
createCopilotRuntimeHandler,
} from "@copilotkit/runtime/v2";
import { createCopilotNodeHandler } from "@copilotkit/runtime/v2/node";
import { All, Inject, Logger, Req, Res } from "@nestjs/common";
import { ApiExcludeController } from "@nestjs/swagger";
import type { Request, Response } from "express";
@ApiExcludeController(true)
@V1Controller("/copilotkit")
export class CopilotKitController {
private readonly logger = new Logger(CopilotKitController.name);
@All()
async copilotkit(
@Req() req: Request,
@Res() res: Response,
) {
const builtInAgent = new BuiltInAgent({
model: "openai:gpt-5.4-mini",
});
const runtime = new CopilotRuntime({
agents: { default: builtInAgent }, //,
intelligence: new CopilotKitIntelligence({
apiKey: "fake",
}),
// Threads are per-user. Without this, every visitor shares one history.
identifyUser: (request) => ({
id: request.headers.get("x-user-id") ?? "anonymous",
name: request.headers.get("x-user-name") ?? "Anonymous",
}),
});
const handler = createCopilotNodeHandler(
createCopilotRuntimeHandler({
runtime,
basePath: "/api/v1/copilotkit",
}),
);
return handler(req, res);
}
}
export const CopilotKitApiControllerModule = createControllerModule(
CopilotKitController,
[CopilotKitModule],
);
curl --url 'http://127.0.0.1:3333/api/v1/copilotkit' \
-H 'Accept: */*' \
-H 'Accept-Language: en-US,en;q=0.5' \
-H 'Cache-Control: no-cache' \
-H 'Connection: keep-alive' \
-H 'Content-Type: application/json' \
-H 'DNT: 1' \
-H 'Origin: http://localhost:3000' \
-H 'Pragma: no-cache' \
-H 'Referer: http://localhost:3000/' \
-H 'Sec-Fetch-Dest: empty' \
-H 'Sec-Fetch-Mode: cors' \
-H 'Sec-Fetch-Site: cross-site' \
-H 'Sec-GPC: 1' \
-H 'User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/152.0.0.0 Safari/537.36' \
-H 'sec-ch-ua: "Chromium";v="152", "Not?A_Brand";v="24", "Brave";v="152"' \
-H 'sec-ch-ua-mobile: ?0' \
-H 'sec-ch-ua-platform: "macOS"' \
--data-raw '{"method":"info"}'
✅ Expected Behavior
return normally
❌ Actual Behavior
/api/v1/copilotkit hung
Screenshots
No response
𝌚 CopilotKit Version
server side
npm ls | grep "@copilotkit"
├── @copilotkit/runtime@1.70.0 -> ./node_modules/.pnpm/@copilotkit+runtime@1.70.0_@cfworker+json-schema@4.1.1_@langchain+core@1.2.9_@opentelem_de5cf5235a9d6d68a70fb5c89ec0b6c1/node_modules/@copilotkit/runtime
├── @copilotkit/shared@1.70.0 -> ./node_modules/.pnpm/@copilotkit+shared@1.70.0_@ag-ui+core@0.0.59/node_modules/@copilotkit/shared
web site
npm ls | grep "@copilotkit"
├── @copilotkit/react-core@1.56.4
├── @copilotkit/react-ui@1.56.4
├── @copilotkit/runtime@1.56.4
📄 Logs (Optional)
server side log
2026-09-02 11:21:20.964 - 01a06022-af40-7aa2-8fda-3859e0c1ff19 - DEBUG [LoggingInterceptor] POST=>/api/v1/copilotkit | query: {} | params: {} | body: {"method":"info"}
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start with the NodeFetchHandler path used by createCopilotNodeHandler and createCopilotRuntimeHandler in the provided NestJS controller. Reproduce the hang with the supplied curl request and compare the handler's behavior for the {"method":"info"} payload. Done means the /api/v1/copilotkit request returns normally instead of remaining open.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- node.js, typescript
- Domain
- api, backend
- Issue type
- Bug
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 50/100