{"record":{"id":"7b7c2f50743076f1","repo":"jaegertracing/jaeger","slug":"failed-to-get-token-from-file-w","errorCode":null,"errorMessage":"failed to get token from file: %w","messagePattern":"failed to get token from file: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/auth/tokenloader.go","lineNumber":63,"sourceCode":"\t\tcachedToken = strings.TrimRight(string(b), \"\\r\\n\")\n\t\tlastRead = now\n\t\treturn cachedToken, nil\n\t}\n}\n\n// TokenProvider creates a token provider that handles file loading and error handling consistently.\nfunc TokenProvider(path string, interval time.Duration, logger *zap.Logger) (func() string, error) {\n\treturn TokenProviderWithTime(path, interval, logger, time.Now) // Use real time.Now in production\n}\n\n// TokenProviderWithTime creates a token provider with injectable time (for testing)\nfunc TokenProviderWithTime(path string, interval time.Duration, logger *zap.Logger, timeFn func() time.Time) (func() string, error) {\n\tloader := cachedFileTokenLoader(path, interval, timeFn)\n\n\t// current token load\n\tcurrentToken, err := loader()\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to get token from file: %w\", err)\n\t}\n\n\t// currentToken is the last successfully loaded token, held so it can be\n\t// returned as a fallback if a later reload fails. The returned closure is\n\t// invoked by the auth RoundTripper on every HTTP request and may run\n\t// concurrently, so access is guarded by mu. A mutex (rather than an\n\t// atomic.Pointer/atomic.Value) keeps this hot path allocation-free.\n\tvar mu sync.Mutex\n\n\treturn func() string {\n\t\tnewToken, err := loader()\n\n\t\tmu.Lock()\n\t\tdefer mu.Unlock()\n\t\tif err != nil {\n\t\t\tlogger.Warn(\"Token reload failed\", zap.Error(err))\n\t\t\treturn currentToken\n\t\t}","sourceCodeStart":45,"sourceCodeEnd":81,"githubUrl":"https://github.com/jaegertracing/jaeger/blob/806f4447841ecdb60519f408b004a599d515f437/internal/auth/tokenloader.go#L45-L81","documentation":"TokenProviderWithTime in internal/auth/tokenloader.go:63 wraps errors from the initial token load with this message. It creates a cached file token loader and immediately calls it once; if that first read of the token file fails, the provider cannot be constructed and the error (which internally wraps \"failed to read token file\") is returned. Callers include TokenProvider (production) and the auth setup path initTokenAuthWithTime.","triggerScenarios":"Calling auth.TokenProvider(path, interval, logger) or TokenProviderWithTime(path, interval, logger, timeFn) where the initial loader() call fails because the token file at path is missing, unreadable, or is a directory.","commonSituations":"Service startup in Kubernetes before the projected secret/token volume is populated; misconfigured token file path in the HTTP auth settings; running the binary locally without creating the token file; permissions changed on the secret file.","solutions":["Ensure the token file exists and is readable before starting the service; fix the configured path if wrong","For Kubernetes, confirm the secret is mounted and populated (kubectl describe pod; check the mount path) and add an init container if ordering matters","Re-run with the file in place — the error occurs only at provider construction, so once the file is readable, TokenProvider succeeds","Inspect the wrapped inner error (failed to read token file: <os error>) to distinguish ENOENT vs EACCES and fix accordingly"],"exampleFix":"// before\n// provider, err := auth.TokenProvider(\"/wrong/path/token\", time.Minute, logger)\n// after\n// const tokenPath = \"/var/run/secrets/token\" // path that actually exists\n// provider, err := auth.TokenProvider(tokenPath, time.Minute, logger)\n// if err != nil { logger.Fatal(\"auth init failed\", zap.Error(err)) }","handlingStrategy":"try-catch","validationCode":"// fail fast at startup with a clear message if the token file is missing\nif _, err := os.Stat(tokenPath); err != nil {\n\treturn nil, fmt.Errorf(\"token file %s not found (check secret mount): %w\", tokenPath, err)\n}","typeGuard":null,"tryCatchPattern":"tokenFn, err := auth.TokenProviderWithTime(path, interval, logger, time.Now)\nif err != nil {\n\tvar pe *fs.PathError\n\tif errors.As(err, &pe) && errors.Is(pe.Err, fs.ErrNotExist) {\n\t\tlogger.Sugar().Fatalf(\"token file %q missing; fix the path or secret mount\", path)\n\t}\n\treturn fmt.Errorf(\"init token auth: %w\", err)\n}","preventionTips":["Validate the token path at config-parse time, before service wiring","In Kubernetes, add an initContainer or readiness gate that waits for the secret file to appear","Distinguish ENOENT vs EACCES by inspecting the wrapped fs.PathError to fix path vs permission issues","Keep a deployment test that starts the service with a real mounted secret to catch path drift"],"tags":["auth","token","startup","file-io"],"backgroundTag":"token-file-unreadable","analyzedSha":"806f4447841ecdb60519f408b004a599d515f437","analyzedAt":"2026-09-01T02:39:22.140Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T05:18:18.240Z"}