hashicorp/terraform · warning
operation canceled
Error message
operation canceled
What it means
Returned by Meta.RunOperation (meta.go:493) when a SECOND interrupt is received. The first signal on m.ShutdownCh triggers a graceful op.Stop(); if the operator hits Ctrl-C again while waiting (line 517 branch), the code calls op.Cancel() for a hard cancel, waits up to 5s, and returns errors.New("operation canceled"). It signals the operation was forcibly terminated rather than completing.
Source
Thrown at internal/command/meta.go:530
// Notify the user
opReq.View.Interrupted()
// Still get the result, since there is still one
select {
case <-m.ShutdownCh:
opReq.View.FatalInterrupt()
// cancel the operation completely
op.Cancel()
// the operation should return asap
// but timeout just in case
select {
case <-op.Done():
case <-time.After(5 * time.Second):
}
return nil, errors.New("operation canceled")
case <-op.Done():
// operation completed after Stop
}
case <-op.Done():
// operation completed normally
}
return op, nil
}
// contextOpts returns the options to use to initialize a Terraform
// context with the settings from this Meta.
func (m *Meta) contextOpts() (*terraform.ContextOpts, error) {
workspace, err := m.Workspace()
if err != nil {
return nil, err
}View on GitHub (pinned to c9def3e214)
Solutions
- Press Ctrl-C once and wait for graceful shutdown; only interrupt again if the operation is truly hung.
- If a provider routinely ignores Stop, upgrade the provider plugin or check for stuck external API calls.
- For automation, send a single SIGINT and poll the process exit rather than double-signaling.
Example fix
# before: double Ctrl-C -> hard cancel, partial state possible ^C^C # after: single interrupt, let graceful Stop complete ^C # wait for 'Interrupt received' then clean exit
Defensive patterns
Strategy: try-catch
Validate before calling
// No pre-validation prevents a double-SIGINT; instead structure signal handling. sigCh := make(chan os.Signal, 1) signal.Notify(sigCh, os.Interrupt)
Try / catch
op, err := meta.RunOperation(b, opReq)
if err != nil && err.Error() == "operation canceled" {
// double-interrupt hard-cancel; surface partial-state risk to the operator
log.Println("operation forcibly cancelled; verify state consistency")
} Prevention
- Send Ctrl-C once and wait for graceful shutdown; double-interrupt forces cancel and can leave partial state.
- In automation, send a single SIGINT and poll for process exit rather than re-signaling.
When it happens
Trigger: Pressing Ctrl-C twice (or sending SIGINT twice) during a long-running `terraform apply`, `terraform plan`, `terraform destroy`, or `terraform refresh` — the first initiates graceful shutdown, the second forces cancellation.
Common situations: Operator impatient during a slow apply and mashing Ctrl-C; CI runner sending SIGINT twice on timeout/job cancel; a hung provider that ignores graceful Stop, prompting a second interrupt.
Related errors
AI-assisted analysis of hashicorp/terraform@c9def3e214 (2026-08-07).
Data as JSON: /api/errors/0448f3fdae487320.
Report an issue: GitHub.