hashicorp/terraform · warning

interrupted - last error

Error message

interrupted - last error: %v

What it means

Surfaced by the communicator Retry loop when the operation context was cancelled (context.Canceled) before the connection/command succeeded. The %v is the last retryable error encountered before interruption. It distinguishes a user/manual interrupt from a timeout (separate message). This is the SSH/provisioner retry wrapper, not the Terraform run context.

Solutions

  1. If intentional, no fix needed — the interrupt was honoured.
  2. If accidental, re-run terraform apply; the resource state is preserved and the provisioner will retry on the next apply if configured with on_failure = continue or via taint.
  3. Address the underlying last error shown in %v so the host becomes reachable faster next time (e.g. security group, user_data timing).
Defensive patterns

Strategy: retry

Try / catch

// If you wrap terraform in Go, distinguish cancel from other errors:
err := runApply(ctx, opts)
if err != nil && strings.Contains(err.Error(), "interrupted - last error") {
    // user-initiated cancel; surface cleanly, optionally offer resume
    return status.Error(codes.Canceled, err.Error())
}

Prevention

When it happens

Trigger: The user pressed Ctrl-C during a remote-exec provisioner run or file upload, cancelling the connection block's context. Also when a parent context is cancelled programmatically while Retry() is backing off between attempts.

Common situations: Interrupting a long-running provisioner that was stuck retrying SSH connections to a not-yet-ready host; CI pipeline cancellation while provisioners execute; a wrapper tool cancelling the apply context.

Related errors


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

Appendix: source

Thrown at internal/communicator/communicator.go:164

		}
	}()

	// Wait for completion
	select {
	case <-ctx.Done():
	case <-doneCh:
	}

	var lastErr error
	// Check if we got an error executing
	if ev, ok := errVal.Load().(errWrap); ok {
		lastErr = ev.E
	}

	// Check if we have a context error to check if we're interrupted or timeout
	switch ctx.Err() {
	case context.Canceled:
		return fmt.Errorf("interrupted - last error: %v", lastErr)
	case context.DeadlineExceeded:
		return fmt.Errorf("timeout - last error: %v", lastErr)
	}

	if lastErr != nil {
		return lastErr
	}
	return nil
}

View on GitHub (pinned to d32a084675)