fatedier/frp · error

localPath is required

Error message

localPath is required

What it means

Validation error from validateStaticFilePluginOptions: the static_file plugin is configured but LocalPath is empty. The static_file plugin serves a local directory over HTTP from the client; the directory to serve is mandatory. This check runs during client-side proxy config validation.

Source

Thrown at pkg/config/v1/validation/plugin.go:64

}

func validateHTTPS2HTTPPluginOptions(c *v1.HTTPS2HTTPPluginOptions) error {
	if c.LocalAddr == "" {
		return errors.New("localAddr is required")
	}
	return nil
}

func validateHTTPS2HTTPSPluginOptions(c *v1.HTTPS2HTTPSPluginOptions) error {
	if c.LocalAddr == "" {
		return errors.New("localAddr is required")
	}
	return nil
}

func validateStaticFilePluginOptions(c *v1.StaticFilePluginOptions) error {
	if c.LocalPath == "" {
		return errors.New("localPath is required")
	}
	return nil
}

func validateUnixDomainSocketPluginOptions(c *v1.UnixDomainSocketPluginOptions) error {
	if c.UnixPath == "" {
		return errors.New("unixPath is required")
	}
	return nil
}

func validateTLS2RawPluginOptions(c *v1.TLS2RawPluginOptions) error {
	if c.LocalAddr == "" {
		return errors.New("localAddr is required")
	}
	return nil
}

View on GitHub (pinned to 6c8a8d0a97)

Solutions

  1. Add localPath = "/srv/files" (absolute directory path to expose) to the plugin options.
  2. Optionally add stripPrefix = "static" and htmlWelcome = true for the desired serving behavior.
  3. Verify the directory exists and the frpc process has read permission on it.

Example fix

# before
[[proxies]]
name = "files"
type = "tcp"
remotePort = 9000
[proxies.plugin]
type = "static_file"

# after
[[proxies]]
name = "files"
type = "tcp"
remotePort = 9000
[proxies.plugin]
type = "static_file"
localPath = "/srv/files"
stripPrefix = "files"
htmlWelcome = true
Defensive patterns

Strategy: validation

Validate before calling

if pluginType == "static_file" && pluginOpts.LocalPath == "" {
    return errors.New("static_file plugin requires localPath")
}

Type guard

func staticFileComplete(o *v1.StaticFilePluginOptions) bool {
    return o != nil && o.LocalPath != ""
}

Try / catch

if err := validation.ValidateProxyConfigurerForClient(cfg); err != nil {
    if strings.Contains(err.Error(), "localPath is required") {
        // add localPath = "/srv/files" to the plugin options
    }
    return err
}

Prevention

When it happens

Trigger: A proxy with plugin = "static_file" whose plugin options omit localPath — e.g. only stripPrefix or htmlWelcome was set, or the plugin options table was not attached to the proxy so all fields are defaults.

Common situations: Quick file-sharing setups where the author sets the plugin type but forgets the served directory; renaming localPath to path or root in the config; the localPath key placed outside the [proxies.plugin] table.

Related errors


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