hashicorp/nomad · error
cannot toggle global mode
Error message
cannot toggle global mode
What it means
A validation error from ACLToken.Validate on update: when updating an existing token, the Global flag is immutable. Nomad rejects an update whose Global value differs from the existing token's Global value.
Source
Thrown at nomad/structs/acl.go:812
}
// Create a time duration which details the time-til-expiry, so we can
// check this against the regions max and min values.
expiresIn := a.ExpirationTime.Sub(a.CreateTime)
if expiresIn > maxTTL {
mErr.Errors = append(mErr.Errors,
fmt.Errorf("expiration time cannot be more than %s in the future (was %s)",
maxTTL, expiresIn))
} else if expiresIn < minTTL {
mErr.Errors = append(mErr.Errors,
fmt.Errorf("expiration time cannot be less than %s in the future (was %s)",
minTTL, expiresIn))
}
}
default:
if existing.Global != a.Global {
mErr.Errors = append(mErr.Errors, errors.New("cannot toggle global mode"))
}
if existing.ExpirationTTL != a.ExpirationTTL {
mErr.Errors = append(mErr.Errors, errors.New("cannot update expiration TTL"))
}
if a.ExpirationTime != nil {
if !existing.ExpirationTime.Equal(*a.ExpirationTime) {
mErr.Errors = append(mErr.Errors, errors.New("cannot update expiration time"))
}
}
}
return mErr.ErrorOrNil()
}
// HasExpirationTime checks whether the ACL token has an expiration time value
// set.
func (a *ACLToken) HasExpirationTime() bool {View on GitHub (pinned to 482b49bf1a)
Solutions
- Keep the existing token's Global value unchanged on update
- If the region scope must change, delete and recreate the token with the desired Global setting
- Set Global to the same value read from the existing token before submitting the update
Example fix
// before update := existing update.Global = !existing.Global // toggling scope // after update := existing // keep update.Global as-is; recreate token if scope must change apiClient.ACL().Delete(existing.AccessorID, nil) newToken.Global = desiredScope apiClient.ACL().Create(newToken, nil)
Defensive patterns
Strategy: validation
Validate before calling
if existing != nil && existing.Global != update.Global {
return errors.New("Global is immutable; recreate the token to change region scope")
} Type guard
func globalFlagStable(existing, update *structs.ACLToken) bool {
return existing == nil || existing.Global == update.Global
} Try / catch
if err := update.Validate(minTTL, maxTTL, existing); err != nil {
if strings.Contains(err.Error(), "cannot toggle global mode") {
update.Global = existing.Global
err = update.Validate(minTTL, maxTTL, existing)
}
} Prevention
- Copy the Global flag verbatim from the existing token on update
- Hide/disable the global toggle in edit UIs; only show it at creation
- To change scope, delete and recreate the token
When it happens
Trigger: Calling ACL Upsert (update) on an existing token where the new token flips Global from true to false or vice versa.
Common situations: Scripts copying a global token into a local-region edit (or the reverse); UIs exposing the global checkbox on token edit forms; automation that normalizes tokens and rewrites the global field.
Related errors
- cannot update expiration TTL
- token name too long
- client token missing policies or roles
- management token cannot be associated with policies or roles
- token type must be client or management
AI-assisted analysis of hashicorp/nomad@482b49bf1a (2026-09-04).
Data as JSON: /api/errors/680c503356e41c32.
Report an issue: GitHub.