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

  1. Verify token generation uses crypto/rand with sufficient entropy (not a seeded/time-based source)
  2. Retry the whole CreateAccessGrant call once; a transient collision resolving between attempts is fine
  3. Audit and prune stale/duplicate grant rows in the repo
  4. 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

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


AI-assisted analysis of Tencent/WeKnora@988cbb0330 (2026-09-02). Data as JSON: /api/errors/0c54c5c355a55334. Report an issue: GitHub.