hashicorp/nomad · error

acl token lookup failed: missing accessor id

Error message

acl token lookup failed: missing accessor id

What it means

A validation error from StateStore.ACLTokenByAccessorID: the caller passed an empty accessor ID string. The store refuses the lookup up-front rather than doing a pointless table scan that would match nothing. It is a caller-input bug, not a state problem.

Source

Thrown at nomad/state/state_store.go:6436

	txn := s.db.WriteTxnMsgT(msgType, index)
	defer txn.Abort()

	// Delete the tokens
	for _, id := range ids {
		if _, err := txn.DeleteAll("acl_token", "id", id); err != nil {
			return fmt.Errorf("deleting acl token failed: %v", err)
		}
	}
	if err := txn.Insert("index", &IndexEntry{"acl_token", index}); err != nil {
		return fmt.Errorf("index update failed: %v", err)
	}
	return txn.Commit()
}

// ACLTokenByAccessorID is used to lookup a token by accessor ID
func (s *StateStore) ACLTokenByAccessorID(ws memdb.WatchSet, id string) (*structs.ACLToken, error) {
	if id == "" {
		return nil, fmt.Errorf("acl token lookup failed: missing accessor id")
	}

	txn := s.db.ReadTxn()

	watchCh, existing, err := txn.FirstWatch("acl_token", "id", id)
	if err != nil {
		return nil, fmt.Errorf("acl token lookup failed: %v", err)
	}
	ws.Add(watchCh)

	// If the existing token is nil, this indicates it does not exist in state.
	if existing == nil {
		return nil, nil
	}

	// Assert the token type which allows us to perform additional work on the
	// token that is needed before returning the call.
	token := existing.(*structs.ACLToken)

View on GitHub (pinned to 482b49bf1a)

Solutions

  1. Check that the accessor ID is non-empty before calling the store (strings.TrimSpace + len check).
  2. At the API layer, reject requests with a missing token early with a 400/permission-denied instead of reaching the state store.
  3. Audit call sites so empty IDs short-circuit with a domain error rather than the store sentinel.

Example fix

// before
token, err := store.ACLTokenByAccessorID(ws, req.SecretToken)
// after
if req.SecretToken == "" {
    return structs.NewErrRPCCoded(400, "missing token secret ID")
}
token, err := store.ACLTokenByAccessorID(ws, req.SecretToken)
Defensive patterns

Strategy: validation

Validate before calling

func canLookupByAccessor(id string) bool {
    return strings.TrimSpace(id) != ""
}
// before calling:
// if !canLookupByAccessor(accessorID) { return errors.New("missing accessor id") }

Type guard

func hasAccessorID(t *struct.ACLToken) bool {
    return t != nil && t.AccessorID != ""
}

Try / catch

if accessorID == "" {
    return fmt.Errorf("acl token lookup skipped: accessor id required")
}
token, err := store.ACLTokenByAccessorID(ws, accessorID)
if err != nil { return err }

Prevention

When it happens

Trigger: Calling ACLTokenByAccessorID with "" — e.g., resolving a token from an HTTP request whose X-Nomad-Token header is empty, or code that did not check a struct field before lookup.

Common situations: Clients sending requests without a token header; config where a token variable was never set; fuzzer/test callers omitting the ID; handlers that strip empty strings after trimming whitespace.

Related errors


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