hashicorp/terraform · critical
confirmFunc must not be nil
Error message
confirmFunc must not be nil
What it means
Programmer-error panic in backendMigrateState: after the switch over source/destination emptiness, confirmFunc must have been assigned (backendMigrateEmptyConfirm for empty-destination, backendMigrateNonEmptyConfirm for both-non-empty, etc.). If none of the cases matched, confirmFunc stays nil and the function panics rather than dereferencing a nil function pointer later.
Source
Thrown at internal/command/meta_backend_migrate.go:443
// this later prompt for Cloud, even though we do still need it
// for state backends.
confirmFunc = func(statemgr.Full, statemgr.Full, *backendMigrateOpts) (bool, error) {
return true, nil // the answer is implied to be "yes" if we reached this point
}
} else {
log.Print("[TRACE] backendMigrateState: destination workspace has empty state, so might copy source workspace state")
confirmFunc = m.backendMigrateEmptyConfirm
}
// Both states are non-empty, meaning we need to determine which
// state should be used and update accordingly.
case !source.Empty() && !destination.Empty():
log.Print("[TRACE] backendMigrateState: both source and destination workspaces have states, so might overwrite destination with source")
confirmFunc = m.backendMigrateNonEmptyConfirm
}
if confirmFunc == nil {
panic("confirmFunc must not be nil")
}
if !opts.force {
// Abort if we can't ask for input.
if !m.input {
log.Print("[TRACE] backendMigrateState: can't prompt for input, so aborting migration")
return errors.New(strings.TrimSpace(errInteractiveInputDisabled))
}
// Confirm with the user whether we want to copy state over
confirm, err := confirmFunc(sourceState, destinationState, opts)
if err != nil {
log.Print("[TRACE] backendMigrateState: error reading input, so aborting migration")
return err
}
if !confirm {
log.Print("[TRACE] backendMigrateState: user cancelled at confirmation prompt, so aborting migration")
return nilView on GitHub (pinned to d32a084675)
Solutions
- Report as a Terraform bug; include the backend types and whether either state was empty.
- Workaround: ensure at least one side (source or destination) has non-empty state before running terraform state migrate / init -migrate-state.
- Try terraform state push/pull to seed one side and avoid the empty/empty branch.
Example fix
// before (library code)
if confirmFunc == nil {
panic("confirmFunc must not be nil")
}
// after (defensive)
if confirmFunc == nil {
return fmt.Errorf("no migration strategy determined for source-empty=%v dest-empty=%v", source.Empty(), destination.Empty())
} Defensive patterns
Strategy: try-catch
Try / catch
// Defensive: return an error instead of panicking on unhandled case
if confirmFunc == nil {
return fmt.Errorf("no migration strategy for source-empty=%v dest-empty=%v", source.Empty(), destination.Empty())
} Prevention
- Ensure at least one side of a migration has non-empty state before running.
- Report empty/empty or other unhandled combinations as a Terraform bug.
- Use terraform state push/pull to seed state as a workaround.
When it happens
Trigger: The switch failed to assign confirmFunc for a particular combination of source/destination state presence (e.g. both empty, or some other combination the code did not anticipate).
Common situations: Edge case in state migration where both source and destination states are empty, or a refactor that changed the case conditions without covering all branches.
Related errors
- Can't serialize backend configuration as JSON: %s
- State migration failed: %w
- nil config passed to StateStoreProviderFactoryFromConfigStat
- init (determineIfProviderTrusted): unexpected provider locat
- Unexpected command type in confirmProviderIsTrusted; this is
AI-assisted analysis of hashicorp/terraform@d32a084675 (2026-08-11).
Data as JSON: /api/errors/8a34a03fc104ff89.
Report an issue: GitHub.