grpc/grpc-go · error
policyFile( ) read failed
Error message
policyFile(%s) read failed: %v
What it means
Returned by FileWatcherInterceptor.updateInternalInterceptor (grpc_authz_server_interceptors.go:175) when os.ReadFile(options.PolicyFile) fails; the underlying error is wrapped with the file path. This is invoked both at construction time (NewFileWatcherWithOptions) and on every refresh tick (run goroutine). On refresh failure the previously loaded interceptor is kept, so authorization continues with the last good policy; at construction time the error propagates to the caller and the watcher is not started.
Solutions
- Confirm the path is absolute and the file exists and is readable by the process uid (ls -l, stat).
- Ensure mounted config (Kubernetes ConfigMap/secret, volume) is available before app start; use a readiness check or retry-on-startup.
- After fixing, let the file watcher self-heal on the next tick (it logs a warning and keeps the old policy); only a construction-time failure blocks startup.
- If using a relative path, switch to an absolute path or resolve relative to the config directory explicitly.
Example fix
// before
fw, err := authz.NewFileWatcher("policy.json", 10*time.Second) // CWD-dependent
// after
fw, err := authz.NewFileWatcher("/etc/app/authz/policy.json", 10*time.Second) Defensive patterns
Strategy: validation
Validate before calling
if _, err := os.Stat(policyPath); err != nil {
log.Fatalf("authz policy file not accessible: %v", err)
}
fw, err := authz.NewFileWatcher(policyPath, refresh) Try / catch
fw, err := authz.NewFileWatcher(policyPath, refresh)
if err != nil {
if strings.Contains(err.Error(), "read failed") {
// check existence/permissions; the running watcher keeps the prior policy on refresh errors
}
} Prevention
- Use absolute paths; confirm the file exists and is readable by the process uid.
- Ensure mounted config (ConfigMap/secret) is present before process start.
- Rely on the file watcher's self-healing: refresh errors keep the last good policy.
When it happens
Trigger: Policy file does not exist, is not readable (permissions), path is a directory, or the path is on a filesystem that is temporarily unavailable; also symlink breakage or container volume mount not yet ready at startup.
Common situations: Wrong/relative path in a container where CWD differs; ConfigMap/secret not mounted yet when the process starts; file replaced atomically with a brief window of ENOENT; permission mismatch (mode 0600 owned by another uid); refresh interval firing during a deploy that swaps the file.
Related errors
- "allow_rules" is not present
- "allow_rules
- authz: authorization policy file path is empty
- authz: requires refresh interval
- : "name" is not present
AI-assisted analysis of grpc/grpc-go@0c51461d27 (2026-08-11).
Data as JSON: /api/errors/bd711cd84488ac5d.
Report an issue: GitHub.
Appendix: source
Thrown at authz/grpc_authz_server_interceptors.go:175
logger.Warningf("authorization policy reload status err: %v", err)
}
select {
case <-ctx.Done():
ticker.Stop()
return
case <-ticker.C:
}
}
}
// updateInternalInterceptor checks if the policy file that is watching has changed,
// and if so, updates the internalInterceptor with the policy. Unlike the
// constructor, if there is an error in reading the file or parsing the policy, the
// previous internalInterceptors will not be replaced.
func (i *FileWatcherInterceptor) updateInternalInterceptor() error {
policyContents, err := os.ReadFile(i.options.PolicyFile)
if err != nil {
return fmt.Errorf("policyFile(%s) read failed: %v", i.options.PolicyFile, err)
}
if bytes.Equal(i.policyContents, policyContents) {
return nil
}
i.policyContents = policyContents
policyContentsString := string(policyContents)
interceptor, err := NewStatic(policyContentsString)
if err != nil {
return err
}
atomic.StorePointer(&i.internalInterceptor, unsafe.Pointer(interceptor))
logger.Infof("authorization policy reload status: successfully loaded new policy %v", policyContentsString)
if i.options.OnPolicyUpdate != nil {
i.options.OnPolicyUpdate(policyContentsString)
}
return nil
}
View on GitHub (pinned to 0c51461d27)