hashicorp/nomad · error

root key state %q is invalid

Error message

root key state %q is invalid

What it means

RootKeyMeta.Validate checks that State is one of the five recognized lifecycle states: inactive, active, rekeying, deprecated, or prepublished. Any other string (including empty) is rejected with this formatted error that echoes the offending value.

Source

Thrown at nomad/structs/keyring.go:411

	out := *rkm
	return &out
}

func (rkm *RootKeyMeta) Validate() error {
	if rkm == nil {
		return fmt.Errorf("root key metadata is required")
	}
	if rkm.KeyID == "" || !helper.IsUUID(rkm.KeyID) {
		return fmt.Errorf("root key UUID is required")
	}
	if rkm.Algorithm == "" {
		return fmt.Errorf("root key algorithm is required")
	}
	switch rkm.State {
	case RootKeyStateInactive, RootKeyStateActive,
		RootKeyStateRekeying, RootKeyStateDeprecated, RootKeyStatePrepublished:
	default:
		return fmt.Errorf("root key state %q is invalid", rkm.State)
	}
	return nil
}

// KeyEncryptionKeyWrapper is a flattened version of the WrappedRootKeys struct
// that gets serialized to disk for a keyset when using the legacy on-disk
// keystore with the AEAD KMS wrapper. This struct includes the server-specific
// key-wrapping key (KEK). This struct should never be sent over RPC or written
// to Raft.
type KeyEncryptionKeyWrapper struct {
	Meta *RootKeyMeta

	Provider                 string             `json:"Provider,omitempty"`
	ProviderID               string             `json:"ProviderID,omitempty"`
	WrappedDataEncryptionKey *wrapping.BlobInfo `json:"WrappedDEK,omitempty"`
	WrappedRSAKey            *wrapping.BlobInfo `json:"WrappedRSAKey,omitempty"`
	KeyEncryptionKey         []byte             `json:"KEK,omitempty"`

View on GitHub (pinned to 482b49bf1a)

Solutions

  1. Set State to one of: "inactive", "active", "rekeying", "deprecated", or "prepublished" (exact lowercase constants in nomad/structs/keyring.go).
  2. Use structs.NewRootKeyMeta() to get a valid default state (inactive/active) instead of hand-building metadata.
  3. Fix casing/typos — the match is exact and case-sensitive.

Example fix

// before
meta := &structs.RootKeyMeta{State: "Active"}
// after
meta := &structs.RootKeyMeta{State: structs.RootKeyStateActive} // "active"
Defensive patterns

Strategy: validation

Validate before calling

validStates := map[structs.RootKeyState]bool{
    structs.RootKeyStateInactive: true, structs.RootKeyStateActive: true,
    structs.RootKeyStateRekeying: true, structs.RootKeyStateDeprecated: true,
    structs.RootKeyStatePrepublished: true,
}
if !validStates[meta.State] {
    return fmt.Errorf("invalid root key state %q", meta.State)
}

Try / catch

if err := meta.Validate(); err != nil {
    if strings.Contains(err.Error(), "root key state") {
        return fmt.Errorf("state must be one of inactive|active|rekeying|deprecated|prepublished: %w", err)
    }
    return err
}

Prevention

When it happens

Trigger: Submitting a root key whose State field is "", misspelled ("actve"), capitalized ("Active"), or a state from a different system; also occurs when older clients send keys without a state field.

Common situations: Manual API calls to root-key endpoints with hand-written JSON; scripts importing keys with custom state labels; version skew where the client predates a state value the server accepts.

Understand the failure class

Background: Invalid enum value errors: "Unknown type", "Invalid scope", "must be one of" — when a string is not on the library's allowed list — this error's family across 23 libraries.

Related errors


AI-assisted analysis of hashicorp/nomad@482b49bf1a (2026-09-04). Data as JSON: /api/errors/7a8cc127265c0b25. Report an issue: GitHub.