grpc/grpc-go · error
authz: requires refresh interval(%v) greater than 0s
Error message
authz: requires refresh interval(%v) greater than 0s
What it means
Returned by authz.NewFileWatcherWithOptions (grpc_authz_server_interceptors.go:140) when RefreshDuration is <= 0. The file watcher uses time.NewTicker with this duration to periodically reload the policy; a zero or negative duration would panic the ticker, so the constructor rejects it.
Source
Thrown at authz/grpc_authz_server_interceptors.go:140
// that contains JSON string of authorization policy and a refresh duration to
// specify the amount of time between policy refreshes.
func NewFileWatcher(file string, duration time.Duration) (*FileWatcherInterceptor, error) {
return NewFileWatcherWithOptions(FileWatcherOptions{PolicyFile: file, RefreshDuration: duration, OnPolicyUpdate: nil})
}
// NewFileWatcherWithOptions returns a new FileWatcherInterceptor from a set of
// options.
//
// # Experimental
//
// Notice: This API is EXPERIMENTAL and may be changed or removed in a
// later release.
func NewFileWatcherWithOptions(options FileWatcherOptions) (*FileWatcherInterceptor, error) {
if options.PolicyFile == "" {
return nil, fmt.Errorf("authz: authorization policy file path is empty")
}
if options.RefreshDuration <= time.Duration(0) {
return nil, fmt.Errorf("authz: requires refresh interval(%v) greater than 0s", options.RefreshDuration)
}
i := &FileWatcherInterceptor{options: options}
if err := i.updateInternalInterceptor(); err != nil {
return nil, err
}
ctx, cancel := context.WithCancel(context.Background())
i.cancel = cancel
// Create a background go routine for policy refresh.
go i.run(ctx)
return i, nil
}
func (i *FileWatcherInterceptor) run(ctx context.Context) {
ticker := time.NewTicker(i.options.RefreshDuration)
for {
if err := i.updateInternalInterceptor(); err != nil {
logger.Warningf("authorization policy reload status err: %v", err)
}View on GitHub (pinned to 03255a9237)
Solutions
- Set RefreshDuration to a positive value such as 10*time.Second or 1*time.Minute.
- Default the duration to a sane positive value when it is unset in config.
- Validate duration > 0 before calling the constructor and surface a clear config error.
- If you do not want periodic reload, use authz.NewStatic (one-shot) instead of the file watcher.
Example fix
// before
az, err := authz.NewFileWatcherWithOptions(
authz.FileWatcherOptions{PolicyFile: path}) // RefreshDuration == 0
// after
dur := cfg.RefreshDuration
if dur <= 0 {
dur = 30 * time.Second
}
az, err := authz.NewFileWatcherWithOptions(
authz.FileWatcherOptions{PolicyFile: path, RefreshDuration: dur}) Defensive patterns
Strategy: validation
Validate before calling
if options.RefreshDuration <= 0 {
options.RefreshDuration = 30 * time.Second
} Try / catch
if _, err := authz.NewFileWatcherWithOptions(opts); err != nil {
if strings.Contains(err.Error(), "refresh interval") {
opts.RefreshDuration = 30 * time.Second
}
} Prevention
- Default RefreshDuration to a positive value at the config layer.
- Use authz.NewStatic when periodic reload is not needed.
- Always populate the whole FileWatcherOptions struct.
When it happens
Trigger: Calling NewFileWatcher(file, 0), NewFileWatcher(file, -time.Second), or NewFileWatcherWithOptions with an uninitialized RefreshDuration (the zero value time.Duration(0)).
Common situations: FileWatcherOptions struct constructed without setting RefreshDuration; a config that conditionally sets the duration but leaves it zero when the condition is false; passing time.Duration from a parsed value that defaulted to 0.
Related errors
- authz: authorization policy file path is empty
- policyFile(%s) read failed: %v
- missing server_listener_resource_name_template in the bootst
- "headers" %d: "key" is not present
- "headers" %d: unsupported "key" %s
AI-assisted analysis of grpc/grpc-go@03255a9237 (2026-08-07).
Data as JSON: /api/errors/5a2e57ff75c667dd.
Report an issue: GitHub.