fatedier/frp · error · ErrInvalidArgument

invalid argument: frpc has no config file path

Error message

invalid argument: frpc has no config file path

What it means

Returned by serviceConfigManager.ReloadFromFile when frpc has no configFilePath — frpc was started without a -c config file (e.g. via admin API-created inline config, environment-only config, or programmatic embedding) so there is no file to reload. It wraps configmgmt.ErrInvalidArgument so callers can classify it.

Source

Thrown at client/config_manager.go:28

	"github.com/fatedier/frp/client/proxy"
	"github.com/fatedier/frp/pkg/config"
	"github.com/fatedier/frp/pkg/config/source"
	v1 "github.com/fatedier/frp/pkg/config/v1"
	"github.com/fatedier/frp/pkg/config/v1/validation"
	"github.com/fatedier/frp/pkg/util/log"
)

type serviceConfigManager struct {
	svr *Service
}

func newServiceConfigManager(svr *Service) configmgmt.ConfigManager {
	return &serviceConfigManager{svr: svr}
}

func (m *serviceConfigManager) ReloadFromFile(strict bool) error {
	if m.svr.configFilePath == "" {
		return fmt.Errorf("%w: frpc has no config file path", configmgmt.ErrInvalidArgument)
	}

	result, err := config.LoadClientConfigResult(m.svr.configFilePath, strict)
	if err != nil {
		return fmt.Errorf("%w: %v", configmgmt.ErrInvalidArgument, err)
	}

	proxyCfgsForValidation, visitorCfgsForValidation := config.FilterClientConfigurers(
		result.Common,
		result.Proxies,
		result.Visitors,
	)
	proxyCfgsForValidation = config.CompleteProxyConfigurers(proxyCfgsForValidation)
	visitorCfgsForValidation = config.CompleteVisitorConfigurers(visitorCfgsForValidation)

	if _, err := validation.ValidateAllClientConfig(result.Common, proxyCfgsForValidation, visitorCfgsForValidation, m.svr.unsafeFeatures); err != nil {
		return fmt.Errorf("%w: %v", configmgmt.ErrInvalidArgument, err)
	}

View on GitHub (pinned to 6c8a8d0a97)

Solutions

  1. If you want file-based reload, start frpc with -c /path/to/frpc.toml so configFilePath is set
  2. If config is API-managed, use the admin API's config endpoints to update config instead of /api/reload
  3. Library users: load config from a known path and construct the service with that path so reload works

Example fix

# before
frpc
# later: curl -X POST localhost:7400/api/reload -> error

# after
frpc -c /etc/frp/frpc.toml
# now: curl -X POST localhost:7400/api/reload works
Defensive patterns

Strategy: type-guard

Validate before calling

// Only expose the reload endpoint when a config file backs the service
if frpcConfigFilePath == "" {
    // skip/503 the /api/reload handler; manage config through the admin API instead
}

Type guard

func canReloadFromFile(svc *client.Service) bool {
    return svc != nil && svc.ConfigFilePath() != ""
}

Try / catch

if err := configManager.ReloadFromFile(strict); err != nil {
    if errors.Is(err, configmgmt.ErrInvalidArgument) && strings.Contains(err.Error(), "no config file path") {
        // service was started API-configured; use API config update, not file reload
    }
}

Prevention

When it happens

Trigger: Starting frpc with only env vars or a config pushed via the admin API, then calling the /api/reload endpoint; embedding frpc as a library (client.NewService) without setting configFilePath; invoking ReloadFromFile on a service constructed from parsed config objects.

Common situations: Kubernetes deployments that inject config via API and later trigger a reload; automation scripts calling the reload endpoint on API-configured instances; library users expecting reload to re-read a file that was never registered.

Related errors


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