Tencent/WeKnora · error
failed to allocate unique resource access token
Error message
failed to allocate unique resource access token
What it means
CreateAccessGrant retries inserting a grant with a freshly generated random token; on repeated unique-constraint violations it exhausts the loop and returns this error. It means the token generator collided with existing tokens on every attempt — astronomically unlikely randomly, so it usually indicates seeded/deterministic tokens or a broken entropy source.
Source
Thrown at internal/application/service/resource.go:235
// derived one is not usable. Mint a fresh random token.
for attempt := 0; attempt < 4; attempt++ {
token, tokenErr := randomResourceToken()
if tokenErr != nil {
return "", tokenErr
}
grant := &types.ResourceAccessGrant{
TokenHash: resourceLocationHash(token),
ResourceID: resource.ID,
AccessScope: "read",
ExpiresAt: time.Now().UTC().Add(ttl),
}
if err := s.repo.CreateGrant(ctx, grant); err == nil {
return token, nil
} else if !isUniqueViolation(err) {
return "", err
}
}
return "", fmt.Errorf("failed to allocate unique resource access token")
}
// reuseOrCreateDerivedGrant returns the token of a live grant for resourceID,
// creating the row on first use within the current window. It returns ("", nil)
// when the caller must fall back to a random token.
//
// The token is derived rather than random so it can be recomputed without ever
// storing it: the table holds only the hash, as before, and the plaintext token
// cannot be reconstructed from a database dump without SYSTEM_AES_KEY.
// Authorization still lives entirely in the row — a revoked or expired grant
// stops resolving even though the token derives to the same value.
func (s *resourceCatalog) reuseOrCreateDerivedGrant(
ctx context.Context, resourceID string, ttl time.Duration,
) (string, error) {
token, expiresAt, ok := derivedGrantToken(resourceID, ttl)
if !ok {
return "", nil
}View on GitHub (pinned to 988cbb0330)
Solutions
- Verify token generation uses crypto/rand with sufficient entropy (not a seeded/time-based source)
- Retry the whole CreateAccessGrant call once; a transient collision resolving between attempts is fine
- Audit and prune stale/duplicate grant rows in the repo
- Increase token length/alphabet if the keyspace is small
Example fix
// before
token := fmt.Sprintf("tok-%d", time.Now().UnixNano())
// after
token := "tok-" + base64.RawURLEncoding.EncodeToString(randomBytes(32)) Defensive patterns
Strategy: retry
Validate before calling
// No caller-side validation possible; ensure token source quality before calling.
if !highEntropyToken(token) { return errors.New("token generator too weak") } Type guard
func highEntropyToken(t string) bool { return len(t) >= 32 } Try / catch
token, err := catalog.CreateAccessGrant(ctx, ref, ttl)
if err != nil && strings.Contains(err.Error(), "failed to allocate unique resource access token") {
return ErrTokenExhausted // alert: entropy source likely broken
} Prevention
- Use crypto/rand for token generation
- Avoid seeded rand in test harnesses that later run in prod-like paths
- Keep token length >= 128 bits
- Alert on this error: a single occurrence suggests systemic token collision
When it happens
Trigger: Loop of repo.CreateGrant calls each failing with isUniqueViolation(err) until attempts run out; caused by deterministic token seeds, mocking a weak random source, or many tokens with tiny keyspace.
Common situations: Test environments with a fixed rand seed; clock-based token generation; config that shrinks the token alphabet/length; duplicate grant rows never cleaned up.
Related errors
- failed to allocate unique resource handle
- empty qqbot access token: code=%d message=%s
- get token error: code=%d msg=%s
- failed to generate JWT secret: %v
- failed to generate OIDC state signing key: %v
AI-assisted analysis of Tencent/WeKnora@988cbb0330 (2026-09-02).
Data as JSON: /api/errors/0c54c5c355a55334.
Report an issue: GitHub.