gofr-dev/gofr · critical
failed to read token from %s: %w
Error message
failed to read token from %s: %w
What it means
NewFileTokenAuthConfig wraps any failure from readToken (missing file, permission error, or empty token file) as "failed to read token from %s: %w" (file_token_auth.go:98). The token is read eagerly at construction so a bad token path or unreadable file aborts startup instead of failing lazily on the first upstream HTTP call.
Source
Thrown at pkg/gofr/service/file_token_auth.go:98
// The token file is read eagerly: a missing or empty file returns an error so
// misconfiguration is caught at startup rather than at the first upstream call.
// The logger is supplied automatically by NewHTTPService via the
// Observable hook; until it arrives, background-refresh failures are
// silent.
func NewFileTokenAuthConfig(opts ...FileTokenAuthOption) (*FileTokenAuthConfig, error) {
f := &FileTokenAuthConfig{
tokenFilePath: DefaultTokenFilePath,
refreshInterval: defaultRefreshInterval,
done: make(chan struct{}),
}
for _, opt := range opts {
opt(f)
}
token, err := readToken(f.tokenFilePath)
if err != nil {
return nil, fmt.Errorf("failed to read token from %s: %w", f.tokenFilePath, err)
}
f.token = token
go f.refreshLoop()
return f, nil
}
// AddOption implements Options.
func (f *FileTokenAuthConfig) AddOption(h HTTP) HTTP {
return &fileTokenDecorator{source: f, HTTP: h}
}
// SetLogger implements Observable. NewHTTPService calls this with the
// HTTP service's logger so background-refresh failures can be surfaced at WARN
// level. If l does not satisfy logging.Logger (the richer interface with
// Warnf), the logger stays unset and refresh failures remain silent ratherView on GitHub (pinned to 187eb24962)
Solutions
- Read the wrapped cause (os.PathError vs 'token file is empty') to decide between fixing the path and fixing file contents.
- Mount the service-account projected volume or set automountServiceAccountToken: true in the pod spec.
- Pass the correct file via WithTokenFilePath for non-K8s or custom mounts.
- Guard construction at startup so the process fails fast and orchestrators restart it once the volume appears.
Example fix
// before
auth, err := service.NewFileTokenAuthConfig() // default path missing outside K8s
// after
if _, statErr := os.Stat(tokenPath); statErr == nil {
auth, err = service.NewFileTokenAuthConfig(service.WithTokenFilePath(tokenPath))
} Defensive patterns
Strategy: try-catch
Validate before calling
if _, err := os.Stat(tokenPath); err != nil {
return fmt.Errorf("token file %s not available: %w", tokenPath, err)
} Type guard
var pathErr *os.PathError
if errors.As(err, &pathErr) { /* missing/unreadable file vs empty content */ } Try / catch
cfg, err := service.NewFileTokenAuthConfig(opts...)
if err != nil {
if errors.Is(err, errEmptyTokenFile) { /* fix file contents */ }
else if errors.As(err, &pathErr) { /* fix path/mount */ }
return err // fail startup fast
} Prevention
- Set automountServiceAccountToken: true or mount the projected volume explicitly in the pod spec.
- Prefer WithTokenFilePath over relying on the K8s default path in non-K8s environments.
- Treat constructor failure as fatal — the eager read exists so you fail at startup.
- Log the full wrapped error chain (%w) to distinguish missing file from empty file.
When it happens
Trigger: Calling NewFileTokenAuthConfig — directly or via main / NewHTTPService options / tests — when the file at the configured (or default K8s) token path does not exist, is unreadable, or is empty; os.ReadFile returns its error and readToken's errEmptyTokenFile is wrapped here.
Common situations: Running outside Kubernetes with the default /var/run/secrets/kubernetes.io/serviceaccount/token path absent; typo in WithTokenFilePath; token volume not mounted (automountServiceAccountToken: false); file permissions after a security hardening change.
Related errors
AI-assisted analysis of gofr-dev/gofr@187eb24962 (2026-09-01).
Data as JSON: /api/errors/f664c523679d72af.
Report an issue: GitHub.