fatedier/frp · error
failed to read file %s: %v
Error message
failed to read file %s: %v
What it means
FileSource.Resolve() wraps the os.ReadFile error when the configured path cannot be read. The underlying error (permissions, missing file, path too long, etc.) is preserved with %v, so the message tells you both which file failed and why. Content is trimmed of surrounding whitespace, so a token file with a trailing newline is fine.
Source
Thrown at pkg/config/v1/value_source.go:109
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
}
// Validate validates the ExecSource configuration.
func (e *ExecSource) Validate() error {
if e == nil {
return errors.New("execSource cannot be nil")
}
if e.Command == "" {
return errors.New("exec command cannot be empty")
}
for _, env := range e.Env {
if env.Name == "" {View on GitHub (pinned to 6c8a8d0a97)
Solutions
- Verify the file exists and is readable: ls -l /path/to/file and run frp as a user with read permission.
- Use an absolute path in file.path to avoid working-directory surprises.
- If the file is injected asynchronously (sidecar, Vault agent), make frp start after the file exists (initContainer, systemd dependency) — there is no retry built in.
- In containers, double-check the mount target matches file.path exactly.
Example fix
# before (frpc.toml) [auth.token.valueSource] type = "file" file.path = "token.txt" # relative; missing in container # after type = "file" file.path = "/etc/frp/token.txt" # absolute, mounted read-only
Defensive patterns
Strategy: try-catch
Validate before calling
func fileReadable(path string) error {
info, err := os.Stat(path)
if err != nil {
return err
}
if info.IsDir() {
return fmt.Errorf("%s is a directory", path)
}
f, err := os.Open(path)
if err != nil {
return err
}
return f.Close()
} Try / catch
val, err := vs.Resolve(ctx)
if err != nil {
if strings.HasPrefix(err.Error(), "failed to read file") {
// config/startup error: report path and fix mount or permissions; do not retry blindly
log.Fatalf("value source file unreadable: %v", err)
}
return err
} Prevention
- Use absolute paths for token files.
- Add a startup readiness probe that checks the token file exists and is readable.
- In containers, verify the mount path matches file.path and the frp user can read it.
When it happens
Trigger: ValueSource{Type: "file"}.Resolve(ctx) where the path does not exist, is a directory, or is not readable by the frp process user; also triggered by a symlink loop or a path on an unmounted volume at startup.
Common situations: Docker/Kubernetes: token file not mounted into the container, or mounted at a different path than configured; file permissions 0600 owned by root while frpc runs as a non-root user; secret (e.g. a Vault-injected token file) not yet written when frp starts; relative path resolved against a different working directory.
Related errors
- include: parse directory of %s failed: %v
- include: directory of %s not exist
- exec configuration is required when type is 'exec'
- file path cannot be empty
- exec command cannot be empty
AI-assisted analysis of fatedier/frp@6c8a8d0a97 (2026-08-15).
Data as JSON: /api/errors/5260ca0e1cfe43c0.
Report an issue: GitHub.