hashicorp/terraform · critical

unsupported view type: %s

Error message

unsupported view type: %s

What it means

NewStateMigrate (internal/command/views/state_migrate.go:81) switches over arguments.ViewType but ONLY implements ViewHuman; everything else panics 'unsupported view type: %s'. This is reachable because ParseStateMigrate (internal/command/arguments/state_migrate.go:128-132) accepts -json and sets ViewJSON when combined with -input=false.

Source

Thrown at internal/command/views/state_migrate.go:87

	LogMigrationSourceInitializationStart()
	LogMigrationSourceInitializationComplete()
	LogMigrationDestinationInitializationStart()
	LogMigrationDestinationInitializationComplete()

	ProviderInstallationLogger
	ProviderLockingLogger

	StateStoreProviderTrustLogger

	Spacer // The `state migrate` command logs empty lines to space-out different sections of human-readable output
}

func NewStateMigrate(viewType arguments.ViewType, view *View) StateMigrate {
	switch viewType {
	case arguments.ViewHuman:
		return &StateMigrateHuman{view: view}
	default:
		panic(fmt.Sprintf("unsupported view type: %s", viewType))
	}
}

var (
	_ StateMigrate                  = (*StateMigrateHuman)(nil)
	_ ProviderInstallationLogger    = (*StateMigrateHuman)(nil)
	_ StateStoreProviderTrustLogger = (*StateMigrateHuman)(nil)
	_ Spacer                        = (*StateMigrateHuman)(nil)
)

type StateMigrateHuman struct {
	view *View
}

func (s *StateMigrateHuman) Diagnostics(diags tfdiags.Diagnostics) {
	s.view.Diagnostics(diags)
}

View on GitHub (pinned to d32a084675)

Solutions

  1. Do not pass -json to 'terraform state migrate'; this command has no JSON view implementation, so drop the flag (keep -input=false for automation).
  2. Until upstream implements StateMigrateJSON, have your wrapper skip or special-case -json for this subcommand.
  3. Upstream fix: either implement the JSON view (add a case for arguments.ViewJSON) or reject -json during ParseStateMigrate so users get a clean diagnostic instead of a panic.
  4. Pin/avoid the version that exposes this latent bug if your automation cannot be adjusted.

Example fix

// before
func NewStateMigrate(viewType arguments.ViewType, view *View) StateMigrate {
    switch viewType {
    case arguments.ViewHuman:
        return &StateMigrateHuman{view: view}
    default:
        panic(fmt.Sprintf("unsupported view type: %s", viewType))
    }
}

// after (reject the unsupported flag at parse time)
// in arguments/state_migrate.go:
if json {
    diags = diags.Append(tfdiags.Sourceless(tfdiags.Error,
        "Unsupported flag",
        "-json is not supported by 'state migrate'"))
}
Defensive patterns

Strategy: validation

Validate before calling

// In automation wrappers, do not forward -json to 'state migrate'.
func buildStateMigrateArgs(wantJSON bool) []string {
    args := []string{"state", "migrate", "-input=false"}
    // state migrate has NO JSON view; omit -json to avoid the panic.
    _ = wantJSON
    return args
}

Prevention

When it happens

Trigger: Running 'terraform state migrate -input=false -json ...' — the argument parser sets migrate.ViewType = ViewJSON, the conflicting-flags guard only rejects -json when -input=true, so ViewJSON reaches NewStateMigrate and hits the default panic.

Common situations: Automation/CI pipelines that pass -json for machine-readable output on every command including 'state migrate'; wrapping tooling that uniformly adds -input=false -json to non-interactive Terraform runs.

Related errors


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