{"record":{"id":"0634ba30372c8dea","repo":"github/copilot-sdk","slug":"timed-out-gracefully-shutting-down-runtime-after","errorCode":null,"errorMessage":"timed out gracefully shutting down runtime after %s","messagePattern":"timed out gracefully shutting down runtime after (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"go/client.go","lineNumber":614,"sourceCode":"\t\trpcClient := c.RPC\n\t\truntimeShutdownStart := time.Now()\n\t\tshutdownDone := make(chan error, 1)\n\t\tgo func() {\n\t\t\t_, err := rpcClient.Runtime.Shutdown(context.Background())\n\t\t\tshutdownDone <- err\n\t\t}()\n\n\t\tselect {\n\t\tcase err := <-shutdownDone:\n\t\t\tif err != nil {\n\t\t\t\tc.logDebugTiming(runtimeShutdownStart, \"CopilotClient.Stop runtime shutdown failed\")\n\t\t\t\terrs = append(errs, fmt.Errorf(\"failed to gracefully shut down runtime: %w\", err))\n\t\t\t} else {\n\t\t\t\tc.logDebugTiming(runtimeShutdownStart, \"CopilotClient.Stop runtime shutdown complete\")\n\t\t\t}\n\t\tcase <-time.After(runtimeShutdownTimeout):\n\t\t\tc.logDebugTiming(runtimeShutdownStart, \"CopilotClient.Stop runtime shutdown timed out\")\n\t\t\terrs = append(errs, fmt.Errorf(\"timed out gracefully shutting down runtime after %s\", runtimeShutdownTimeout))\n\t\t}\n\t}\n\n\t// The runtime completes all cleanup before responding to runtime.shutdown\n\t// and then leaves termination to us; it deliberately keeps its JSON-RPC\n\t// server alive to send the response and never self-exits. Waiting for a\n\t// self-exit that will never come just wastes time, so terminate the child\n\t// immediately and only wait to reap it.\n\tif c.process != nil && !c.isExternalServer {\n\t\tif err := c.killProcessAndWait(); err != nil {\n\t\t\terrs = append(errs, err)\n\t\t}\n\t}\n\tc.process = nil\n\n\t// Tear down the in-process FFI host (closes the connection and shuts down the\n\t// native runtime). No child process to reap in this mode.\n\tif c.ffiHost != nil {","sourceCodeStart":596,"sourceCodeEnd":632,"githubUrl":"https://github.com/github/copilot-sdk/blob/cd8cf15dc3f9e762615790aaed0a771a0f392755/go/client.go#L596-L632","documentation":"CopilotClient.Stop gives the runtime a fixed window (runtimeShutdownTimeout) to shut down gracefully. If the runtime does not finish in time, Stop appends this timeout error instead of waiting indefinitely.","triggerScenarios":"Calling Stop when the runtime takes longer than runtimeShutdownTimeout to respond to runtime.shutdown.","commonSituations":"Runtime blocked on open tool calls or slow cleanup; heavily loaded host; large session state being torn down.","solutions":["Ensure sessions/tool calls are completed or cancelled before Stop.","Check runtime logs for what is blocking shutdown.","Increase runtimeShutdownTimeout if legitimately slow, or accept the timeout and force-terminate the process.","Upgrade to a runtime version with faster shutdown."],"exampleFix":"// before\nclient.Stop(ctx) // times out silently-ish\n// after\nif err := client.Stop(ctx); err != nil {\n    if strings.Contains(err.Error(), \"timed out gracefully shutting down runtime\") {\n        process.Kill() // force-terminate hung runtime\n    }\n}","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"if err := client.Stop(ctx); err != nil && strings.Contains(err.Error(), \"timed out gracefully\") { process.Kill() }","preventionTips":["Cancel in-flight tool calls before Stop","Budget adequate shutdown time","Monitor for hung runtimes"],"tags":["go","timeout","shutdown"],"backgroundTag":"request-timeout","analyzedSha":"cd8cf15dc3f9e762615790aaed0a771a0f392755","analyzedAt":"2026-09-09T18:32:31.973Z","contentChangedAt":"2026-09-09T18:32:31.973Z","schemaVersion":2},"datasetVersion":"2026-09-15T23:17:13.987Z"}