{"record":{"id":"d642d48fce80e3d6","repo":"apache/beam","slug":"control-channel-closed","errorCode":null,"errorMessage":"Control channel closed.","messagePattern":"Control channel closed\\.","errorType":"console","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"sdks/typescript/src/apache_beam/worker/worker.ts","lineNumber":96,"sourceCode":"  metricsShortIdCache = new MetricsShortIdCache();\n\n  constructor(\n    private id: string,\n    private endpoints: WorkerEndpoints,\n    options: Object = {},\n  ) {\n    const metadata = new grpc.Metadata();\n    metadata.add(\"worker_id\", this.id);\n    this.controlClient = new BeamFnControlClient(\n      endpoints.controlUrl,\n      grpc.ChannelCredentials.createInsecure(),\n      {},\n      {},\n    );\n    this.controlChannel = this.controlClient.control(metadata);\n    this.controlChannel.on(\"data\", this.handleRequest.bind(this));\n    this.controlChannel.on(\"end\", () => {\n      console.warn(\"Control channel closed.\");\n      for (const dataChannel of this.dataChannels.values()) {\n        try {\n          // Best effort.\n          dataChannel.close();\n        } finally {\n        }\n      }\n      for (const stateChannel of this.stateChannels.values()) {\n        try {\n          // Best effort.\n          stateChannel.close();\n        } finally {\n        }\n      }\n    });\n  }\n\n  async wait() {","sourceCodeStart":78,"sourceCodeEnd":114,"githubUrl":"https://github.com/apache/beam/blob/12126d8942aaf848030c478b4c6a28c6af861c66/sdks/typescript/src/apache_beam/worker/worker.ts#L78-L114","documentation":"The Beam TypeScript worker warns 'Control channel closed.' when the gRPC control stream from the Fn API control service ends. The constructor then closes all data channels best-effort. This indicates the runner/controller closed or terminated the control connection, so the worker can no longer receive instructions.","triggerScenarios":"The control gRPC server stream emits 'end' — e.g. the job finishes, the runner shuts down the harness, or the control connection drops unexpectedly.","commonSituations":"Normal pipeline shutdown (benign); network interruption or proxy killing long-lived gRPC streams; the controlling process crashing so the worker's channels end prematurely.","solutions":["If the pipeline completed normally, ignore — this is expected shutdown logging.","If it appears mid-run, check connectivity/proxy keepalive settings between worker and control service and inspect runner logs for harness restarts.","Rely on the runner's retry/restart of workers; ensure the control service address and credentials are correct."],"exampleFix":"// before\nworker without reconnect handling; channel end -> closed permanently\n// after\ncontrolChannel.on(\"end\", () => {\n  if (!shuttingDown) {\n    console.error(\"Control channel closed unexpectedly; restarting worker\");\n    restart();\n  }\n});","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"controlChannel.on(\"end\", () => {\n  if (!shuttingDown) {\n    console.error(\"Control channel closed unexpectedly\");\n    scheduleWorkerRestart();\n  }\n});\ncontrolChannel.on(\"error\", (err) => console.error(\"Control channel error:\", err));","preventionTips":["Configure gRPC keepalive so long-lived control streams survive idle proxies","Verify control service address, TLS, and credentials before launching workers","Check runner/harness logs when this appears mid-job rather than at shutdown"],"tags":["typescript","grpc","stream","worker"],"backgroundTag":"grpc-stream-closed","analyzedSha":"12126d8942aaf848030c478b4c6a28c6af861c66","analyzedAt":"2026-09-13T01:50:10.254Z","contentChangedAt":"2026-09-13T01:50:10.254Z","schemaVersion":2},"datasetVersion":"2026-09-20T03:17:13.778Z"}