hashicorp/terraform · warning

execution halted

Error message

execution halted

What it means

Returned by the internal stopHook on every hook callback once Stop() has been invoked (atomic flag set). It causes Terraform to return HookActionHalt plus an 'execution halted' error, propagating the user's interrupt through the graph walk so in-flight operations wind down. It is the internal mechanism behind Ctrl+C / SIGINT graceful stop.

Solutions

  1. Treat it as expected on interrupt — do not retry the operation automatically; let Terraform finish stopping.
  2. If the halt was unintended, investigate what sent the stop signal (orchestrator, wrapper script, OOM killer sending SIGTERM).
  3. Send a second interrupt (SIGINT) to force a harder stop if graceful halt is itself stuck.
  4. Ensure context handling in your wrapper distinguishes user-initiated stop from real failures.

Example fix

n/a — represents an intentional user/system stop, not a recoverable error. Handle by surfacing 'operation cancelled' to the caller.
Defensive patterns

Strategy: try-catch

Validate before calling

n/a — interruption is external; cannot be pre-validated.

Type guard

func isExecutionHalted(err error) bool {
    return err != nil && err.Error() == "execution halted"
}

Try / catch

// Hook errors surface through the graph walk; check for halt
if err != nil && err.Error() == "execution halted" {
    return errors.New("operation cancelled by user")
}

Prevention

When it happens

Trigger: stopHook.hook() at hook_stop.go:133-138 checks h.Stopped(); if true it returns (HookActionHalt, errors.New("execution halted")). Triggered after Stop() sets the atomic flag, typically from the signal handler.

Common situations: User pressed Ctrl+C (first SIGINT → graceful stop); a parent process sent SIGTERM; an explicit programmatic stop was requested via the Terraform exec interface.

Related errors


AI-assisted analysis of hashicorp/terraform@d32a084675 (2026-08-11). Data as JSON: /api/errors/1f3f0069e4d9b50e. Report an issue: GitHub.

Appendix: source

Thrown at internal/terraform/hook_stop.go:135

func (h *stopHook) StartAction(id HookActionIdentity) (HookAction, error) {
	return h.hook()
}

func (h *stopHook) ProgressAction(id HookActionIdentity, progress string) (HookAction, error) {
	return h.hook()
}

func (h *stopHook) CompleteAction(id HookActionIdentity, err error) (HookAction, error) {
	return h.hook()
}

func (h *stopHook) PolicyResult(addr string, resp policy.EvaluationResponse) (HookAction, error) {
	return h.hook()
}

func (h *stopHook) hook() (HookAction, error) {
	if h.Stopped() {
		return HookActionHalt, errors.New("execution halted")
	}

	return HookActionContinue, nil
}

// reset should be called within the lock context
func (h *stopHook) Reset() {
	atomic.StoreUint32(&h.stop, 0)
}

func (h *stopHook) Stop() {
	atomic.StoreUint32(&h.stop, 1)
}

func (h *stopHook) Stopped() bool {
	return atomic.LoadUint32(&h.stop) == 1
}

View on GitHub (pinned to d32a084675)