hashicorp/terraform · warning

The pattern must have an '*'

Error message

The pattern must have an '*'

What it means

Returned during multi-state-to-TFC workspace renaming when the user-supplied rename pattern does not contain a literal '*' character. The '*' is the placeholder substituted with each source workspace name, so the pattern must include exactly one.

Source

Thrown at internal/command/meta_backend_migrate.go:974

		return "", fmt.Errorf("Please select 1 or 2 as part of this option.")
	}
	if renameWorkspaces == "2" {
		// this means they did not want to rename their workspaces, and we are
		// returning a generic '*' that means use the same workspace name during
		// migration.
		return "*", nil
	}

	pattern, err := m.UIInput().Input(context.Background(), &terraform.InputOpts{
		Id:          "backend-migrate-multistate-to-tfc-pattern",
		Query:       fmt.Sprintf("[reset][bold][yellow]%s[reset]", "How would you like to rename your workspaces?"),
		Description: strings.TrimSpace(tfcInputBackendMigrateMultiToMultiPattern),
	})
	if err != nil {
		return "", fmt.Errorf("Error asking for state migration action: %s", err)
	}
	if !strings.Contains(pattern, "*") {
		return "", fmt.Errorf("The pattern must have an '*'")
	}

	if count := strings.Count(pattern, "*"); count > 1 {
		return "", fmt.Errorf("The pattern '*' cannot be used more than once.")
	}

	return pattern, nil
}

const errMigrateLoadStates = `
Error inspecting states in the %q backend:
    %s

Prior to changing backends, Terraform inspects the source and destination
states to determine what kind of migration steps need to be taken, if any.
Terraform failed to load the states. The data in both the source and the
destination remain unmodified. Please resolve the above error and try again.
`

View on GitHub (pinned to c9def3e214)

Solutions

  1. Re-enter a pattern containing exactly one '*', e.g. 'prefix-*-suffix' or 'migrated-*'.
  2. If you want the original name preserved verbatim, choose '2' (no rename) at the earlier prompt instead.
  3. Do not use regex or '?' — only '*' is supported as the substitution token.

Example fix

// before
// pattern entered: 'newstate'  -> error (no '*')

// after
// pattern entered: 'newstate-*'
Defensive patterns

Strategy: validation

Validate before calling

// Validate the rename pattern contains exactly one '*'
func validPattern(p string) bool {
    return strings.Contains(p, "*") && strings.Count(p, "*") == 1
}
if !validPattern(pattern) {
    return fmt.Errorf("pattern must contain exactly one '*'")
}

Type guard

func isValidRenamePattern(p string) bool {
    return strings.Contains(p, "*") && strings.Count(p, "*") == 1
}

Prevention

When it happens

Trigger: promptMultiStateMigrationPattern: user chose '1' and entered a pattern; `strings.Contains(pattern, "*")` is false. Examples: 'newname', 'prefix-', 'foo-#' all fail because there is no '*'.

Common situations: User misunderstands the pattern syntax and types a literal name without '*'; copy-paste drops the asterisk; user expects regex/glob and types '.' or '?'.

Related errors


AI-assisted analysis of hashicorp/terraform@c9def3e214 (2026-08-07). Data as JSON: /api/errors/0c7ef617bea1c96f. Report an issue: GitHub.