vxcontrol/pentagi · error
token can't be empty
Error message
token can't be empty
What it means
After confirming the Authorization header starts with "Bearer ", the middleware slices off the 7-character prefix and rejects the request when the remainder is empty. This means the client sent `Authorization: Bearer` (or `Bearer ` with only whitespace-stripped empty content) but no actual token value. The middleware cannot authenticate without a credential, so it returns authResultSkip for other mechanisms to attempt.
Source
Thrown at backend/pkg/server/auth/auth_middleware.go:206
c.Set("cpt", "automation")
}
return authResultOk, nil
}
const PrivilegeAutomation = "pentagi.automation"
func (p *AuthMiddleware) tryProtoTokenAuthentication(c *gin.Context) (authResult, error) {
authHeader := c.Request.Header.Get("Authorization")
if authHeader == "" {
return authResultSkip, errors.New("token required")
}
if !strings.HasPrefix(authHeader, "Bearer ") {
return authResultSkip, errors.New("bearer scheme must be used")
}
token := authHeader[7:]
if token == "" {
return authResultSkip, errors.New("token can't be empty")
}
// skip validation if using default salt (for backward compatibility)
if p.globalSalt == "" || p.globalSalt == "salt" {
return authResultSkip, errors.New("token validation disabled with default salt")
}
// try to validate as API token first (new format with JWT signing key)
apiClaims, apiErr := ValidateAPIToken(token, p.globalSalt)
if apiErr != nil {
return authResultFail, errors.New("token is invalid")
}
// check token status and get privileges through cache
status, privileges, err := p.tokenCache.GetStatus(apiClaims.TokenID)
if err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {View on GitHub (pinned to ea665308ba)
Solutions
- Ensure the token variable is actually set before the request: check `echo -n "${API_TOKEN}" | wc -c` is non-zero.
- Send `Authorization: Bearer <non-empty api token>` created from the API tokens settings UI.
- Guard client code: skip the request or fail fast with a clear config error if the token is empty.
- Regenerate an API token if the previous one was deleted from the database.
Example fix
// before
const header = `Bearer ${process.env.API_TOKEN}`;
// after
if (!process.env.API_TOKEN) throw new Error("API_TOKEN is not set");
const header = `Bearer ${process.env.API_TOKEN}`; Defensive patterns
Strategy: validation
Validate before calling
const token = process.env.API_TOKEN ?? "";
if (!token.trim()) throw new Error("API token is empty; refusing to send request");
headers["Authorization"] = `Bearer ${token.trim()}`; Type guard
function hasToken(t: unknown): t is string {
return typeof t === "string" && t.trim().length > 0;
} Try / catch
try {
return await client.request(opts);
} catch (e) {
if (is401(e) && /can't be empty|token required/i.test(e.message)) {
throw new ConfigError("API token missing — check API_TOKEN secret");
}
throw e;
} Prevention
- Fail fast at startup when the token env var/secret is unset or empty.
- Interpolate secrets with ${VAR:-} guards in CI and assert non-empty before deploy.
- Trim tokens read from files to avoid whitespace-only values.
When it happens
Trigger: Sending `Authorization: Bearer` or `Authorization: Bearer ` (trailing space, empty token), typically when a template variable holding the token is empty/unset, e.g. `Bearer ${API_TOKEN}` where API_TOKEN="".
Common situations: CI/CD secret not injected so the token env var is empty; .env file missing the token; string interpolation in a config file silently producing "Bearer "; token deleted from settings and the client cached an empty value.
Related errors
- bearer scheme must be used
- token validation disabled with default salt
- token is invalid
- token not found in database
- token has been revoked
AI-assisted analysis of vxcontrol/pentagi@ea665308ba (2026-09-01).
Data as JSON: /api/errors/b519745c4f81d0da.
Report an issue: GitHub.