vxcontrol/pentagi · warning

Token.InvalidRequest

Token.InvalidRequest

Error message

token with this name already exists

What it means

CreateToken enforces per-user uniqueness of active token names: before generating a token it queries for an existing non-deleted token with the same user_id and name, and if one exists it returns Token.InvalidRequest with 'token with this name already exists'. Names are only unique per user, not globally.

Source

Thrown at backend/pkg/server/services/api_tokens.go:89

		logger.FromContext(c).WithError(err).Errorf("error binding JSON")
		response.Error(c, response.ErrTokenInvalidRequest, err)
		return
	}
	if err := req.Valid(); err != nil {
		logger.FromContext(c).WithError(err).Errorf("error validating JSON")
		response.Error(c, response.ErrTokenInvalidRequest, err)
		return
	}

	if req.Name != nil && *req.Name != "" {
		var existing models.APIToken
		err := s.db.
			Where("user_id = ? AND name = ? AND deleted_at IS NULL", uid, *req.Name).
			First(&existing).
			Error
		if err == nil {
			logger.FromContext(c).Errorf("token with name '%s' already exists for user %d", *req.Name, uid)
			response.Error(c, response.ErrTokenInvalidRequest, errors.New("token with this name already exists"))
			return
		}
	}

	tokenID, err := auth.GenerateTokenID()
	if err != nil {
		logger.FromContext(c).WithError(err).Errorf("error generating token ID")
		response.Error(c, response.ErrInternal, err)
		return
	}

	claims := auth.MakeAPITokenClaims(tokenID, uhash, uid, rid, req.TTL)

	token, err := auth.MakeAPIToken(s.globalSalt, claims)
	if err != nil {
		logger.FromContext(c).WithError(err).Errorf("error signing token")
		response.Error(c, response.ErrInternal, err)
		return

View on GitHub (pinned to ea665308ba)

Solutions

  1. Choose a different, unique name for the new token.
  2. List existing tokens (GET /tokens) and reuse or rename the existing one instead of creating a duplicate.
  3. Soft-delete the old token with the same name (DELETE /tokens/{id}) then re-create it.
  4. Make the creating script idempotent: look up the token by name first and reuse it on 409/invalid-request.

Example fix

// before
POST /tokens {"name":"ci-deploy"}   // duplicate -> error
// after
POST /tokens {"name":"ci-deploy-2026-09"}  // unique name succeeds
Defensive patterns

Strategy: validation

Validate before calling

const names = (await api.get('/tokens')).data.tokens.map(t => t.name).filter(Boolean);
if (names.includes(desiredName)) throw new Error(`token name '${desiredName}' already in use`);

Type guard

function isNameFree(name, existing) { return !existing.some(t => t.name === name); }

Try / catch

try { await api.post('/tokens', { name }); }
catch (e) {
  if (e.response?.data?.code === 'Token.InvalidRequest' && /already exists/.test(e.response.data.message)) {
    name = `${name}-${Date.now()}`; // retry with unique suffix
  } else throw e;
}

Prevention

When it happens

Trigger: POST /tokens with a body {"name": "X"} when the same user already owns an active (not soft-deleted) token named X.

Common situations: Re-running an automation script that creates tokens idempotently by name; UI double-submit; user forgot an existing token with the same label; retry after a partial failure where the first creation actually succeeded.

Related errors


AI-assisted analysis of vxcontrol/pentagi@ea665308ba (2026-09-01). Data as JSON: /api/errors/42745a314b37a555. Report an issue: GitHub.