{"record":{"id":"1f3f0069e4d9b50e","repo":"hashicorp/terraform","slug":"execution-halted-1f3f00","errorCode":null,"errorMessage":"execution halted","messagePattern":"execution halted","errorType":"console","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"internal/terraform/hook_stop.go","lineNumber":135,"sourceCode":"func (h *stopHook) StartAction(id HookActionIdentity) (HookAction, error) {\n\treturn h.hook()\n}\n\nfunc (h *stopHook) ProgressAction(id HookActionIdentity, progress string) (HookAction, error) {\n\treturn h.hook()\n}\n\nfunc (h *stopHook) CompleteAction(id HookActionIdentity, err error) (HookAction, error) {\n\treturn h.hook()\n}\n\nfunc (h *stopHook) PolicyResult(addr string, resp policy.EvaluationResponse) (HookAction, error) {\n\treturn h.hook()\n}\n\nfunc (h *stopHook) hook() (HookAction, error) {\n\tif h.Stopped() {\n\t\treturn HookActionHalt, errors.New(\"execution halted\")\n\t}\n\n\treturn HookActionContinue, nil\n}\n\n// reset should be called within the lock context\nfunc (h *stopHook) Reset() {\n\tatomic.StoreUint32(&h.stop, 0)\n}\n\nfunc (h *stopHook) Stop() {\n\tatomic.StoreUint32(&h.stop, 1)\n}\n\nfunc (h *stopHook) Stopped() bool {\n\treturn atomic.LoadUint32(&h.stop) == 1\n}\n","sourceCodeStart":117,"sourceCodeEnd":153,"githubUrl":"https://github.com/hashicorp/terraform/blob/c9def3e214014c1188faabfc4a5bde5095139765/internal/terraform/hook_stop.go#L117-L153","documentation":"'execution halted' is returned by the internal stopHook at every lifecycle hook boundary (PreApply, PostDiff, PreProvisionInstance, PreRefresh, etc.) once the stop flag has been set. It is Terraform's cooperative-cancellation signal: an interrupt was requested and the graph walker honors it at the next hook point by returning HookActionHalt plus this error, which surfaces as a halted apply/plan.","triggerScenarios":"Returned at internal/terraform/hook_stop.go:135 inside hook() when h.Stopped() is true (atomic flag stop==1, set by Stop()). The hook() method is invoked by every Pre*/Post* hook method on stopHook, so it fires at the next graph step boundary after Stop() is called.","commonSituations":"User pressed Ctrl+C (SIGINT) during `terraform apply`/`plan`. A programmatic Stop() was issued by an embedding application or a watchdog. A long-running operation was canceled by an orchestration layer. A second Ctrl+C forces a harder cancel but the first typically yields this halt at the next hook.","solutions":["Recognize it as intentional cancellation — inspect whether the user/orchestrator requested the stop; if so, no remediation is needed.","If it happens unexpectedly, audit what is calling Context.Stop() / sending signals to the Terraform process.","For apply, the state has already been updated for resources completed before the halt; rerun `terraform apply` to continue and `terraform state list` to verify what was applied.","Run with -auto-approve disabled and watch for the interrupt; if a hook never returns (stuck provider), the halt may be deferred — see the provider's Close behavior."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"// Embedders: only call Context.Stop() in response to a real signal.\nsc := make(chan os.Signal, 1)\nsignal.Notify(sc, os.Interrupt)\ngo func() { <-sc; ctx.Stop() }()","typeGuard":"func isExecutionHalted(err error) bool {\n    return err != nil && err.Error() == \"execution halted\"\n}","tryCatchPattern":"if _, err := ctx.Apply(); err != nil {\n    if isExecutionHalted(err) {\n        // user requested stop; state is consistent up to the halt\n        return nil\n    }\n    return err\n}","preventionTips":["Treat 'execution halted' as expected on Ctrl+C; surface a clean 'interrupted' message.","Audit embedders for spurious Stop() calls.","Re-run apply after an interrupt to resume."],"tags":["hooks","interrupt","cancellation","apply","lifecycle"],"analyzedSha":"c9def3e214014c1188faabfc4a5bde5095139765","analyzedAt":"2026-08-07T15:39:49.278Z","schemaVersion":2},"datasetVersion":"2026-08-07T21:17:07.882Z"}