hashicorp/terraform · error

%q is not a valid state name

Error message

%q is not a valid state name

What it means

Backend.client(name) requires a non-empty workspace name; an empty string produces no valid object key (it would map to '.tfstate'), so the backend rejects it before constructing the remoteClient. Returned from StateMgr, DeleteWorkspace, and any code path that goes through client().

Source

Thrown at internal/backend/remote-state/gcs/backend_state.go:83

// DeleteWorkspace deletes the named workspaces. The "default" state cannot be deleted.
func (b *Backend) DeleteWorkspace(name string, _ bool) tfdiags.Diagnostics {
	var diags tfdiags.Diagnostics
	if name == backend.DefaultStateName {
		return diags.Append(fmt.Errorf("cowardly refusing to delete the %q state", name))
	}

	c, err := b.client(name)
	if err != nil {
		return diags.Append(err)
	}

	return diags.Append(c.Delete())
}

// client returns a remoteClient for the named state.
func (b *Backend) client(name string) (*remoteClient, error) {
	if name == "" {
		return nil, fmt.Errorf("%q is not a valid state name", name)
	}

	return &remoteClient{
		storageClient: b.storageClient,
		bucketName:    b.bucketName,
		stateFilePath: b.stateFile(name),
		lockFilePath:  b.lockFile(name),
		encryptionKey: b.encryptionKey,
		kmsKeyName:    b.kmsKeyName,
	}, nil
}

// StateMgr reads and returns the named state from GCS. If the named state does
// not yet exist, a new state file is created.
func (b *Backend) StateMgr(name string) (statemgr.Full, tfdiags.Diagnostics) {
	var diags tfdiags.Diagnostics

	c, err := b.client(name)

View on GitHub (pinned to c9def3e214)

Solutions

  1. Ensure the caller passes a concrete non-empty workspace name (commonly 'default').
  2. Add a guard before invoking StateMgr/DeleteWorkspace: if name == "" { name = backend.DefaultStateName }.
  3. Trace the caller to find where the empty value originates (env var, flag, list index).

Example fix

// before
mgr, diags := backend.StateMgr(os.Getenv("TF_WORKSPACE"))  // empty when unset

// after
name := os.Getenv("TF_WORKSPACE")
if name == "" { name = backend.DefaultStateName }
mgr, diags := backend.StateMgr(name)
Defensive patterns

Strategy: validation

Validate before calling

name := os.Getenv("TF_WORKSPACE")
if name == "" { name = backend.DefaultStateName }
mgr, diags := backend.StateMgr(name)

Type guard

func isValidStateName(name string) bool { return strings.TrimSpace(name) != "" }

Prevention

When it happens

Trigger: Programmatic use of the Backend interface with StateMgr("") or DeleteWorkspace("", _); a wrapper tool that computes workspace names and produces an empty string.

Common situations: Tooling/automation bugs that pass an unset variable as the workspace name; misconfigured workspace-name interpolation in HCL-driven automation.

Related errors


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