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, err

View on GitHub (pinned to 482b49bf1a)

Solutions

  1. If the role already exists, call ACLRoles.Update(role) instead of Create.
  2. If you truly want a new role, clear role.ID (role.ID = "") before Create so the server assigns a fresh ID.
  3. 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

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


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