grpc/grpc-go · error

authz: requires refresh interval

Error message

authz: requires refresh interval(%v) greater than 0s

What it means

Returned by authz.NewFileWatcherWithOptions (grpc_authz_server_interceptors.go:140) when FileWatcherOptions.RefreshDuration is <= 0. The interceptor spawns a background goroutine (run, line 153) that ticks on RefreshDuration via time.NewTicker to re-read the policy file; a zero or negative duration is an invalid ticker interval and is rejected before the goroutine starts.

Solutions

  1. Set a positive RefreshDuration, e.g. 10*time.Second or any interval appropriate to how often your policy file changes.
  2. If you do not want periodic reload, use authz.NewStatic (a one-shot static policy) rather than the file watcher.
  3. Validate the parsed interval before constructing the interceptor and fail fast with a clear message.

Example fix

// before
fw, err := authz.NewFileWatcher("/etc/grpc/policy.json", 0)

// after
fw, err := authz.NewFileWatcher("/etc/grpc/policy.json", 30*time.Second)
Defensive patterns

Strategy: validation

Validate before calling

if refresh <= 0 {
    refresh = 30 * time.Second // sane default
}
fw, err := authz.NewFileWatcher(policyPath, refresh)

Try / catch

fw, err := authz.NewFileWatcher(policyPath, refresh)
if err != nil {
    if strings.Contains(err.Error(), "refresh interval") {
        // set a positive duration and reconstruct
    }
}

Prevention

When it happens

Trigger: Calling NewFileWatcher(file, 0) or NewFileWatcherWithOptions with RefreshDuration unset (defaults to 0 because time.Duration zero value is 0); passing a negative duration; computing the interval from config that yielded 0.

Common situations: Forgetting to set RefreshDuration when using NewFileWatcherWithOptions; env-driven interval parsed as 0 on parse failure; tests that pass 0 for convenience.

Related errors


AI-assisted analysis of grpc/grpc-go@0c51461d27 (2026-08-11). Data as JSON: /api/errors/5a2e57ff75c667dd. Report an issue: GitHub.

Appendix: 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 0c51461d27)