fatedier/frp · error

file path cannot be empty

Error message

file path cannot be empty

What it means

Thrown by FileSource.Validate() when a ValueSource of type "file" has an empty Path. FileSource.Resolve reads the file contents (trimmed) as the resolved value, typically an auth token, so an empty path is rejected before any os.ReadFile attempt.

Source

Thrown at pkg/config/v1/value_source.go:96

	switch v.Type {
	case "file":
		return v.File.Resolve(ctx)
	case "exec":
		return v.Exec.Resolve(ctx)
	default:
		return "", fmt.Errorf("unsupported value source type: %s", v.Type)
	}
}

// Validate validates the FileSource configuration.
func (f *FileSource) Validate() error {
	if f == nil {
		return errors.New("fileSource cannot be nil")
	}

	if f.Path == "" {
		return errors.New("file path cannot be empty")
	}
	return nil
}

// Resolve reads and returns the content from the specified file.
func (f *FileSource) Resolve(_ context.Context) (string, error) {
	if err := f.Validate(); err != nil {
		return "", err
	}

	content, err := os.ReadFile(f.Path)
	if err != nil {
		return "", fmt.Errorf("failed to read file %s: %v", f.Path, err)
	}

	// Trim whitespace, which is important for file-based tokens
	return strings.TrimSpace(string(content)), nil
}

View on GitHub (pinned to 6c8a8d0a97)

Solutions

  1. Set tokenSource.file.path to the absolute path of the token file, e.g. path = "/etc/frp/token"
  2. Verify the file exists and frpc/frps can read it (check permissions) after fixing the path
  3. Run frpc verify -c ./frpc.toml to confirm the config parses and validates
  4. If the token is produced by a command, switch to type = "exec" with a command instead

Example fix

# before
[auth]
tokenSource.type = "file"
[auth.tokenSource.file]

# after
[auth]
tokenSource.type = "file"
[auth.tokenSource.file]
path = "/etc/frp/token"
Defensive patterns

Strategy: validation

Validate before calling

if vs := cfg.Auth.TokenSource; vs != nil && vs.Type == "file" && vs.File != nil {
    if strings.TrimSpace(vs.File.Path) == "" {
        return fmt.Errorf("tokenSource.file.path is empty")
    }
}

Type guard

func hasFileSource(vs *v1.ValueSource) bool {
    return vs != nil && vs.Type == "file" && vs.File != nil && vs.File.Path != ""
}

Prevention

When it happens

Trigger: tokenSource.type = "file" with tokenSource.file.path omitted or set to ""; Go literal v1.ValueSource{Type: "file", File: &v1.FileSource{}} with Path unset; templated config where the path variable expands to empty.

Common situations: Copying a file-based token example but leaving the path placeholder; secrets-in-file setups (e.g. Docker/Kubernetes secret mounted paths) where the mount path was changed but the config was not; relative paths that were intended but never filled in.

Related errors


AI-assisted analysis of fatedier/frp@6c8a8d0a97 (2026-08-15). Data as JSON: /api/errors/bff0f08a56312b93. Report an issue: GitHub.