henrygd/beszel · critical
must set TOKEN or TOKEN_FILE
Error message
must set TOKEN or TOKEN_FILE
What it means
getToken resolves the authentication token in order: already-loaded client.token, then the TOKEN env var, then the file pointed to by TOKEN_FILE. If no token source is configured at all, it throws this error telling the user they must set TOKEN or TOKEN_FILE. The library will not be able to authenticate the WebSocket connection without a token.
Source
Thrown at agent/client.go:84
client.hubRequest = &common.HubRequest[cbor.RawMessage]{}
client.fingerprint = agent.getFingerprint()
return client, nil
}
// getToken returns the token for the WebSocket client.
// It first checks the TOKEN environment variable, then the TOKEN_FILE environment variable.
// If neither is set, it returns an error.
func getToken() (string, error) {
// get token from env var
token, _ := utils.GetEnv("TOKEN")
if token != "" {
return token, nil
}
// get token from file
tokenFile, _ := utils.GetEnv("TOKEN_FILE")
if tokenFile == "" {
return "", errors.New("must set TOKEN or TOKEN_FILE")
}
tokenBytes, err := os.ReadFile(tokenFile)
if err != nil {
return "", err
}
return parseTokenFile(string(tokenBytes), tokenFile)
}
// parseTokenFile reads a single token from TOKEN_FILE.
// Blank lines and comments are ignored. Multiple tokens are rejected because
// the agent supports only one outbound hub connection.
func parseTokenFile(contents, path string) (string, error) {
var token string
for line := range strings.Lines(contents) {
line = strings.TrimSpace(line)
if len(line) == 0 || strings.HasPrefix(line, "#") {
continue
}View on GitHub (pinned to b38fb7dafa)
Solutions
- Set TOKEN=<jwt> in the environment before starting the agent.
- Or set TOKEN_FILE=/path/to/token and place the token in that file.
- Ensure the service definition (systemd unit, Docker env) forwards these variables to the process.
- Add a preflight config check that fails with a clear message listing both accepted variables.
Example fix
// before export HUB_URL="wss://hub" ./agent # -> must set TOKEN or TOKEN_FILE // after export HUB_URL="wss://hub" export TOKEN_FILE="/etc/agent/token" ./agent
Defensive patterns
Strategy: validation
Validate before calling
token, _ := os.LookupEnv("TOKEN")
tokenFile, hasFile := os.LookupEnv("TOKEN_FILE")
if token == "" && (!hasFile || tokenFile == "") {
return fmt.Errorf("agent auth not configured: set TOKEN or TOKEN_FILE")
}
if hasFile && tokenFile != "" {
if _, err := os.Stat(tokenFile); err != nil {
return fmt.Errorf("TOKEN_FILE %s not readable: %w", tokenFile, err)
}
} Try / catch
client, err := newWebSocketClient(agent)
if err != nil {
if strings.Contains(err.Error(), "TOKEN or TOKEN_FILE") {
log.Fatal("auth config missing: provide TOKEN env var or a readable TOKEN_FILE")
}
log.Fatal(err)
} Prevention
- Provision the token file during install/deployment before the service starts.
- Prefer TOKEN_FILE over inline TOKEN so secrets don't leak into process listings.
- Ensure the service user can read the token file (permissions, mount).
- Add a config preflight that lists all required auth variables in one error message.
When it happens
Trigger: newWebSocketClient calls getToken with no client.token set, TOKEN unset, and TOKEN_FILE unset or empty.
Common situations: Fresh install where only HUB_URL was configured; token provisioning step skipped in CI; running the agent under a service manager that sanitizes env vars; TOKEN_FILE set but pointing to an empty path due to another config bug (note: a set-but-wrong TOKEN_FILE produces a different read error).
Related errors
- HUB_URL environment variable not set
- no matching fingerprints
- invalid signature - check KEY value
- data directory not found
- hub not verified
AI-assisted analysis of henrygd/beszel@b38fb7dafa (2026-08-31).
Data as JSON: /api/errors/ba8907e961d140a0.
Report an issue: GitHub.