{"record":{"id":"ba8907e961d140a0","repo":"henrygd/beszel","slug":"must-set-token-or-token-file","errorCode":null,"errorMessage":"must set TOKEN or TOKEN_FILE","messagePattern":"must set TOKEN or TOKEN_FILE","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"agent/client.go","lineNumber":84,"sourceCode":"\tclient.hubRequest = &common.HubRequest[cbor.RawMessage]{}\n\tclient.fingerprint = agent.getFingerprint()\n\n\treturn client, nil\n}\n\n// getToken returns the token for the WebSocket client.\n// It first checks the TOKEN environment variable, then the TOKEN_FILE environment variable.\n// If neither is set, it returns an error.\nfunc getToken() (string, error) {\n\t// get token from env var\n\ttoken, _ := utils.GetEnv(\"TOKEN\")\n\tif token != \"\" {\n\t\treturn token, nil\n\t}\n\t// get token from file\n\ttokenFile, _ := utils.GetEnv(\"TOKEN_FILE\")\n\tif tokenFile == \"\" {\n\t\treturn \"\", errors.New(\"must set TOKEN or TOKEN_FILE\")\n\t}\n\ttokenBytes, err := os.ReadFile(tokenFile)\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\treturn parseTokenFile(string(tokenBytes), tokenFile)\n}\n\n// parseTokenFile reads a single token from TOKEN_FILE.\n// Blank lines and comments are ignored. Multiple tokens are rejected because\n// the agent supports only one outbound hub connection.\nfunc parseTokenFile(contents, path string) (string, error) {\n\tvar token string\n\tfor line := range strings.Lines(contents) {\n\t\tline = strings.TrimSpace(line)\n\t\tif len(line) == 0 || strings.HasPrefix(line, \"#\") {\n\t\t\tcontinue\n\t\t}","sourceCodeStart":66,"sourceCodeEnd":102,"githubUrl":"https://github.com/henrygd/beszel/blob/b38fb7dafa60812cc22e6a84ce313e94f1ce0a32/agent/client.go#L66-L102","documentation":"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.","triggerScenarios":"newWebSocketClient calls getToken with no client.token set, TOKEN unset, and TOKEN_FILE unset or empty.","commonSituations":"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).","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."],"exampleFix":"// before\nexport HUB_URL=\"wss://hub\"\n./agent  # -> must set TOKEN or TOKEN_FILE\n// after\nexport HUB_URL=\"wss://hub\"\nexport TOKEN_FILE=\"/etc/agent/token\"\n./agent","handlingStrategy":"validation","validationCode":"token, _ := os.LookupEnv(\"TOKEN\")\ntokenFile, hasFile := os.LookupEnv(\"TOKEN_FILE\")\nif token == \"\" && (!hasFile || tokenFile == \"\") {\n\treturn fmt.Errorf(\"agent auth not configured: set TOKEN or TOKEN_FILE\")\n}\nif hasFile && tokenFile != \"\" {\n\tif _, err := os.Stat(tokenFile); err != nil {\n\t\treturn fmt.Errorf(\"TOKEN_FILE %s not readable: %w\", tokenFile, err)\n\t}\n}","typeGuard":null,"tryCatchPattern":"client, err := newWebSocketClient(agent)\nif err != nil {\n\tif strings.Contains(err.Error(), \"TOKEN or TOKEN_FILE\") {\n\t\tlog.Fatal(\"auth config missing: provide TOKEN env var or a readable TOKEN_FILE\")\n\t}\n\tlog.Fatal(err)\n}","preventionTips":["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."],"tags":["configuration","authentication","token","environment"],"backgroundTag":"missing-credentials","analyzedSha":"b38fb7dafa60812cc22e6a84ce313e94f1ce0a32","analyzedAt":"2026-08-31T15:10:10.149Z","schemaVersion":2},"datasetVersion":"2026-08-31T19:17:28.585Z"}