{"record":{"id":"c28b553b1c3d5a67","repo":"github/copilot-sdk","slug":"failed-to-gracefully-shut-down-runtime-w","errorCode":null,"errorMessage":"failed to gracefully shut down runtime: %w","messagePattern":"failed to gracefully shut down runtime: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"go/client.go","lineNumber":608,"sourceCode":"\tc.clearGitHubTokenProviders()\n\n\tc.startStopMux.Lock()\n\tdefer c.startStopMux.Unlock()\n\n\tif (c.process != nil || c.ffiHost != nil) && !c.isExternalServer && c.RPC != nil {\n\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}","sourceCodeStart":590,"sourceCodeEnd":626,"githubUrl":"https://github.com/github/copilot-sdk/blob/cd8cf15dc3f9e762615790aaed0a771a0f392755/go/client.go#L590-L626","documentation":"During CopilotClient.Stop, the SDK requests a graceful runtime shutdown and waits for a result. If the shutdown goroutine returns an error, Stop appends this wrapped error, indicating the runtime rejected or failed the shutdown request.","triggerScenarios":"Calling Stop when the runtime.shutdown RPC returns an error (e.g. runtime in a bad state, request failed mid-flight).","commonSituations":"Runtime hung or wedged; JSON-RPC connection broken during shutdown; runtime binary crash during cleanup.","solutions":["Read the wrapped cause for the runtime's shutdown error.","Verify the runtime process is responsive (logs, health check).","If shutdown repeatedly fails, force-kill the runtime process as a last resort.","Upgrade SDK/runtime if the error indicates a known shutdown bug."],"exampleFix":"// before\nclient.Stop(ctx) // ignore partial shutdown errors\n// after\nif err := client.Stop(ctx); err != nil {\n    log.Printf(\"runtime shutdown issue: %v\", err)\n    // consider force-killing the runtime process\n}","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"if err := client.Stop(ctx); err != nil { if strings.Contains(err.Error(), \"gracefully shut down runtime\") { /* check runtime process */ } }","preventionTips":["Ensure runtime process is responsive before Stop","Watch runtime logs during shutdown","Keep SDK/runtime versions matched"],"tags":["go","shutdown","process"],"backgroundTag":"http-error-response","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"}