{"record":{"id":"4bf6de2f0c71f4cc","repo":"hashicorp/terraform","slug":"ephemeral-resources-failed-to-close-during-renew-o","errorCode":null,"errorMessage":"Ephemeral resources failed to Close during renew operations","messagePattern":"Ephemeral resources failed to Close during renew operations","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"internal/resources/ephemeral/ephemeral_resources.go","lineNumber":190,"sourceCode":"\t// All renew loops should have returned, or else we're going to leak\n\t// resources which could be continually renewing, or even interfering with\n\t// the same resources during the next operation.\n\t//\n\t// Use an asynchronous check so we can timeout and report the problem.\n\tdone := make(chan int)\n\tgo func() {\n\t\tr.wg.Wait()\n\t\tclose(done)\n\t}()\n\tselect {\n\tcase <-done:\n\t\t// OK!\n\tcase <-time.After(10 * time.Second):\n\t\t// This is probably harmless a lot of time, but is also indicative of an\n\t\t// ephemeral resource which would be misbehaving. The message isn't\n\t\t// very helpful with no context, so we'll have to rely on correlating\n\t\t// the problem via other log messages.\n\t\tdiags = diags.Append(errors.New(\"Ephemeral resources failed to Close during renew operations\"))\n\t}\n\n\treturn diags\n}\n\ntype resourceInstanceInternal struct {\n\tvalue      cty.Value\n\tconfigBody hcl.Body\n\timpl       ResourceInstance\n\n\trenewCancel func()\n\trenewDiags  tfdiags.Diagnostics\n\trenewMu     sync.Mutex // hold when accessing renewCancel/renewDiags, and while actually renewing\n}\n\n// close halts this instance's asynchronous renewal loop, if any, and then\n// calls Close on the resource instance's implementation object.\n//","sourceCodeStart":172,"sourceCodeEnd":208,"githubUrl":"https://github.com/hashicorp/terraform/blob/c9def3e214014c1188faabfc4a5bde5095139765/internal/resources/ephemeral/ephemeral_resources.go#L172-L208","documentation":"A diagnostic (not a sentinel) emitted by Resources.Close during teardown: after asynchronously closing all active ephemeral resource instances, it waits on the renew WaitGroup with a 10-second timeout. If the renew loops (and their Close calls) do not all drain within 10s, this warning-level diagnostic is appended to signal that one or more ephemeral resources likely leaked. The code comment notes this is 'probably harmless a lot of the time' but indicates a misbehaving provider.","triggerScenarios":"Emitted at internal/resources/ephemeral/ephemeral_resources.go:190 when the select on the done channel loses to time.After(10*time.Second) in Resources.Close. The renew loops are started elsewhere (in the renew path of resourceInstanceInternal) and each holds r.wg.","commonSituations":"A provider whose Renew/Close RPC for an ephemeral resource blocks or is very slow (e.g. waiting on an external API). A provider that crashed after opening an ephemeral resource, leaving the renew loop stuck. Heavy load/network latency to the provider exceeding 10s. A provider bug that never returns from Close.","solutions":["Upgrade the provider — a Close/Renew hang is typically a provider-side bug that gets fixed in releases.","Check TF_LOG for the provider process: look for the last Renew/Close RPC and whether the provider subprocess is still alive or crashed.","Reduce the number/scope of ephemeral resources open at once, or shorten renew intervals if configurable, to lighten teardown pressure.","If you author the provider, ensure Renew and Close return promptly and honor context cancellation.","If purely cosmetic in your setup and resources do eventually clean up, you may safely proceed but report it as a provider issue."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"// No pre-check; this is a teardown-time diagnostic. Mitigate by ensuring\n// provider Renew/Close are fast and context-aware before opening ephemeral resources.","typeGuard":"func isEphemeralCloseTimeout(diags tfdiags.Diagnostics) bool {\n    return diags.Err() != nil && strings.Contains(diags.Err().Error(), \"failed to Close during renew operations\")\n}","tryCatchPattern":"diags := resources.Close(ctx)\nif isEphemeralCloseTimeout(diags) {\n    // log and continue; report the provider as potentially leaking\n    log.Printf(\"[WARN] ephemeral resources may have leaked: %s\", diags.Err())\n}","preventionTips":["Author providers whose Renew and Close honor context cancellation and return promptly.","Keep ephemeral resource counts bounded per operation.","Watch provider logs for stuck Renew/Close RPCs and file provider issues early."],"tags":["ephemeral-resources","provider","renew","timeout","resource-leak"],"analyzedSha":"c9def3e214014c1188faabfc4a5bde5095139765","analyzedAt":"2026-08-07T15:39:49.278Z","schemaVersion":2},"datasetVersion":"2026-08-07T21:17:07.882Z"}