Skip to content

Commit 7029dfa

Browse files
Mark-C-Hallclaude
andauthored
Fix nil pointer dereference in backend state migration (#38028)
* fix: handle all StateMgr errors during backend migration Fixes a nil pointer dereference panic that occurs during backend migration when StateMgr returns an error other than ErrDefaultWorkspaceNotSupported. The bug occurred because the code only checked for the specific ErrDefaultWorkspaceNotSupported error. When any other error occurred (such as permission errors like storage.objects.get access denied), destinationState remained nil, but the code continued and attempted to call destinationState.RefreshState(), causing a panic. This fix adds an else clause to catch and return all other errors from StateMgr, preventing the nil pointer dereference and providing users with a clear error message instead of a crash. Fixes #24100 * Add changelog entry for backend migration nil pointer fix 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]> --------- Co-authored-by: Claude <[email protected]>
1 parent 810f497 commit 7029dfa

File tree

2 files changed

+36
-25
lines changed

2 files changed

+36
-25
lines changed
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
kind: BUG FIXES
2+
body: 'backend: Fix nil pointer dereference crash during `terraform init -migrate-state` when the destination backend returns a permission error'
3+
time: 2025-12-23T18:45:16.000000Z
4+
custom:
5+
Issue: "38027"

internal/command/meta_backend_migrate.go

Lines changed: 31 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -282,37 +282,43 @@ func (m *Meta) backendMigrateState_s_s(opts *backendMigrateOpts) error {
282282

283283
var err error
284284
destinationState, sDiags := opts.Destination.StateMgr(opts.destinationWorkspace)
285-
if sDiags.HasErrors() && sDiags.Err().Error() == backend.ErrDefaultWorkspaceNotSupported.Error() {
286-
// If the backend doesn't support using the default state, we ask the user
287-
// for a new name and migrate the default state to the given named state.
288-
destinationState, err = func() (statemgr.Full, error) {
289-
log.Print("[TRACE] backendMigrateState: destination doesn't support a default workspace, so we must prompt for a new name")
290-
name, err := m.promptNewWorkspaceName(opts.DestinationType)
291-
if err != nil {
292-
return nil, err
293-
}
285+
if sDiags.HasErrors() {
286+
if sDiags.Err().Error() == backend.ErrDefaultWorkspaceNotSupported.Error() {
287+
// If the backend doesn't support using the default state, we ask the user
288+
// for a new name and migrate the default state to the given named state.
289+
destinationState, err = func() (statemgr.Full, error) {
290+
log.Print("[TRACE] backendMigrateState: destination doesn't support a default workspace, so we must prompt for a new name")
291+
name, err := m.promptNewWorkspaceName(opts.DestinationType)
292+
if err != nil {
293+
return nil, err
294+
}
294295

295-
// Update the name of the destination state.
296-
opts.destinationWorkspace = name
296+
// Update the name of the destination state.
297+
opts.destinationWorkspace = name
297298

298-
destinationState, sDiags := opts.Destination.StateMgr(opts.destinationWorkspace)
299-
if sDiags.HasErrors() {
300-
return nil, sDiags.Err()
301-
}
299+
destinationState, sDiags := opts.Destination.StateMgr(opts.destinationWorkspace)
300+
if sDiags.HasErrors() {
301+
return nil, sDiags.Err()
302+
}
302303

303-
// Ignore invalid workspace name as it is irrelevant in this context.
304-
workspace, _ := m.Workspace()
304+
// Ignore invalid workspace name as it is irrelevant in this context.
305+
workspace, _ := m.Workspace()
305306

306-
// If the currently selected workspace is the default workspace, then set
307-
// the named workspace as the new selected workspace.
308-
if workspace == backend.DefaultStateName {
309-
if err := m.SetWorkspace(opts.destinationWorkspace); err != nil {
310-
return nil, fmt.Errorf("Failed to set new workspace: %s", err)
307+
// If the currently selected workspace is the default workspace, then set
308+
// the named workspace as the new selected workspace.
309+
if workspace == backend.DefaultStateName {
310+
if err := m.SetWorkspace(opts.destinationWorkspace); err != nil {
311+
return nil, fmt.Errorf("Failed to set new workspace: %s", err)
312+
}
311313
}
312-
}
313314

314-
return destinationState, nil
315-
}()
315+
return destinationState, nil
316+
}()
317+
} else {
318+
// For any other error, return it immediately to avoid nil pointer dereference
319+
return fmt.Errorf(strings.TrimSpace(
320+
errMigrateSingleLoadDefault), opts.DestinationType, sDiags.Err())
321+
}
316322
}
317323
if err != nil {
318324
return fmt.Errorf(strings.TrimSpace(

0 commit comments

Comments
 (0)