hashicorp/nomad · error
cannot specify ACL role ID
Error message
cannot specify ACL role ID
What it means
ACLRoles.Create() refuses to create a role that already carries an ID, since creation is meant to mint a new server-generated ID. Setting role.ID != "" usually means the caller intended an update, not a create, so the client fails fast to prevent accidentally creating a duplicate role.
Source
Thrown at api/acl.go:279
// ACLRoles returns a new handle on the ACL roles API client.
func (c *Client) ACLRoles() *ACLRoles {
return &ACLRoles{client: c}
}
// List is used to detail all the ACL roles currently stored within state.
func (a *ACLRoles) List(q *QueryOptions) ([]*ACLRoleListStub, *QueryMeta, error) {
var resp []*ACLRoleListStub
qm, err := a.client.query("/v1/acl/roles", &resp, q)
if err != nil {
return nil, nil, err
}
return resp, qm, nil
}
// Create is used to create an ACL role.
func (a *ACLRoles) Create(role *ACLRole, w *WriteOptions) (*ACLRole, *WriteMeta, error) {
if role.ID != "" {
return nil, nil, errors.New("cannot specify ACL role ID")
}
var resp ACLRole
wm, err := a.client.put("/v1/acl/role", role, &resp, w)
if err != nil {
return nil, nil, err
}
return &resp, wm, nil
}
// Update is used to update an existing ACL role.
func (a *ACLRoles) Update(role *ACLRole, w *WriteOptions) (*ACLRole, *WriteMeta, error) {
if role.ID == "" {
return nil, nil, errMissingACLRoleID
}
var resp ACLRole
wm, err := a.client.put("/v1/acl/role/"+role.ID, role, &resp, w)
if err != nil {
return nil, nil, errView on GitHub (pinned to 482b49bf1a)
Solutions
- If the role already exists, call ACLRoles.Update(role) instead of Create.
- If you truly want a new role, clear role.ID (role.ID = "") before Create so the server assigns a fresh ID.
- Restructure upsert logic: try GetByName; if found, Update, else Create with a fresh struct without ID.
Example fix
// before
existing, _, _ := client.ACL().Roles().GetByName("my-role", nil)
existing.Description = "new desc"
_, _, err := client.ACL().Roles().Create(existing, nil) // fails: cannot specify ACL role ID
// after
existing.Description = "new desc"
_, _, err := client.ACL().Roles().Update(existing, nil) Defensive patterns
Strategy: validation
Validate before calling
if role != nil && role.ID != "" {
return fmt.Errorf("use ACLRoles.Update for existing roles; Create refuses role.ID != \"\"")
} Type guard
func isNewRole(r *api.ACLRole) bool { return r != nil && r.ID == "" } Prevention
- Implement upsert as: GetByName -> found ? Update : Create(fresh struct without ID).
- Never reuse server-fetched role structs in Create calls.
- When deserializing roles from JSON for creation, explicitly clear the ID field.
When it happens
Trigger: Calling ACLRoles.Create(role) where role.ID was populated — most often because the code path reuses a role struct fetched via Get/GetByName and passes it to Create instead of Update.
Common situations: Copy/paste of an update block into a create path; an 'upsert' helper that always calls Create first; deserializing a role from JSON that includes its ID and then calling Create.
Understand the failure class
Background: "missing required argument" and "the following required arguments were not provided": what required-argument errors mean and how to fix them — this error's family across 20 libraries.
Related errors
- errMissingACLRoleID
- errMissingACLAuthMethodName
- errMissingACLBindingRuleID
- missing ACL role name
- no one-time token returned
AI-assisted analysis of hashicorp/nomad@482b49bf1a (2026-09-04).
Data as JSON: /api/errors/434f8dc75e080d37.
Report an issue: GitHub.