grpc/grpc-go · error

authz: authorization policy file path is empty

Error message

authz: authorization policy file path is empty

What it means

Returned by authz.NewFileWatcherWithOptions (grpc_authz_server_interceptors.go:137) when FileWatcherOptions.PolicyFile is the empty string. The FileWatcher interceptor needs a file path to read the JSON authorization policy from on startup and on each refresh tick, so an empty path is rejected immediately and no watcher goroutine is started.

Solutions

  1. Provide a non-empty policy file path in FileWatcherOptions.PolicyFile (or the first arg to NewFileWatcher).
  2. Resolve the path from config/flag/env and fail application startup early if it is unset, before constructing the interceptor.
  3. If you do not want file-based policy, use authz.NewStatic(policyJSON) instead of the file watcher.

Example fix

// before
fw, err := authz.NewFileWatcher(policyPath, 10*time.Second)

// after
if policyPath == "" {
    log.Fatal("AUTHZ_POLICY_FILE is required")
}
fw, err := authz.NewFileWatcher(policyPath, 10*time.Second)
Defensive patterns

Strategy: validation

Validate before calling

opts := authz.FileWatcherOptions{PolicyFile: policyPath, RefreshDuration: refresh}
if opts.PolicyFile == "" {
    log.Fatal("authz: policy file path must be set")
}
fw, err := authz.NewFileWatcherWithOptions(opts)

Try / catch

fw, err := authz.NewFileWatcherWithOptions(opts)
if err != nil {
    if strings.Contains(err.Error(), "policy file path is empty") {
        // supply PolicyFile and reconstruct
    }
}

Prevention

When it happens

Trigger: Calling NewFileWatcher("") or NewFileWatcherWithOptions with an unset PolicyFile field; reading the path from an env var or flag that defaulted to empty; constructing the interceptor before configuration loading completes.

Common situations: Flag/env-driven config where the policy path was not supplied in a given environment; wiring code that builds the interceptor unconditionally and supplies the path later; silent default of an empty string.

Related errors


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

Appendix: source

Thrown at authz/grpc_authz_server_interceptors.go:137

}

// NewFileWatcher returns a new FileWatcherInterceptor from a policy file
// 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 {

View on GitHub (pinned to 0c51461d27)