hashicorp/terraform · error

Lock ID should be numerical value, got

Error message

Lock ID should be numerical value, got '%s'

What it means

Thrown by Unlock when the supplied lock ID cannot be parsed as a 64-bit integer. GCS lock IDs are object generation numbers (numeric), so Unlock strconv.ParseInt's the id before using it as a GenerationMatch precondition.

Solutions

  1. Re-read the lock info from the lock file and copy the numeric ID/generation exactly.
  2. Run `terraform force-unlock` and let it read the ID from state rather than typing it.
  3. Verify the lock file JSON's 'ID' field is the generation number.

Example fix

// before
terraform force-unlock tf-default
// after — use the numeric generation from the lock file
terraform force-unlock 1234567890
Defensive patterns

Strategy: validation

Validate before calling

// Validate the lock ID is numeric before calling Unlock.
if _, err := strconv.ParseInt(id, 10, 64); err != nil {
    return fmt.Errorf("lock ID %q is not the numeric generation; copy ID from the lock file", id)
}

Type guard

func isNumericLockID(id string) bool {
    _, err := strconv.ParseInt(id, 10, 64)
    return err == nil
}

Prevention

When it happens

Trigger: Unlock(id) is called with a non-numeric string — e.g., a hand-typed lock ID, a UUID from a different backend, a corrupted env var, or an empty string.

Common situations: User passes the workspace name or a UUID to force-unlock instead of the numeric generation; CI script reads the wrong field from the lock file JSON; lock ID was truncated when copied.

Related errors


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

Appendix: source

Thrown at internal/backend/remote-state/gcs/client.go:131

		}
		return w.Close()
	}()

	if err != nil {
		return "", c.lockError(fmt.Errorf("writing %q failed: %v", c.lockFileURL(), err))
	}

	info.ID = strconv.FormatInt(w.Attrs().Generation, 10)

	return info.ID, nil
}

func (c *remoteClient) Unlock(id string) error {
	ctx := context.TODO()

	gen, err := strconv.ParseInt(id, 10, 64)
	if err != nil {
		return fmt.Errorf("Lock ID should be numerical value, got '%s'", id)
	}

	if err := c.lockFile().If(storage.Conditions{GenerationMatch: gen}).Delete(ctx); err != nil {
		return c.lockError(err)
	}

	return nil
}

func (c *remoteClient) lockError(err error) *statemgr.LockError {
	lockErr := &statemgr.LockError{
		Err: err,
	}

	info, infoErr := c.lockInfo()
	if infoErr != nil {
		lockErr.Err = errors.Join(lockErr.Err, infoErr)
	} else {

View on GitHub (pinned to d32a084675)