fatedier/frp · error
ErrConflict
ErrConflict
Error message
conflict
What it means
configmgmt.ErrConflict is the frpc config-manager sentinel for state collisions. CreateProxy/CreateVisitor wrap it (%w) around the underlying store error when a proxy or visitor with the same name already exists — specifically the store source's ErrAlreadyExists bubbling up. The admin HTTP layer maps it to 409 Conflict (client/http/controller.go:64).
Source
Thrown at client/configmgmt/types.go:14
package configmgmt
import (
"errors"
"time"
"github.com/fatedier/frp/client/proxy"
v1 "github.com/fatedier/frp/pkg/config/v1"
)
var (
ErrInvalidArgument = errors.New("invalid argument")
ErrNotFound = errors.New("not found")
ErrConflict = errors.New("conflict")
ErrStoreDisabled = errors.New("store disabled")
ErrApplyConfig = errors.New("apply config failed")
)
type ConfigManager interface {
ReloadFromFile(strict bool) error
ReadConfigFile() (string, error)
WriteConfigFile(content []byte) error
GetProxyStatus() []*proxy.WorkingStatus
IsStoreProxyEnabled(name string) bool
StoreEnabled() bool
GetProxyConfig(name string) (v1.ProxyConfigurer, bool)
GetVisitorConfig(name string) (v1.VisitorConfigurer, bool)
ListStoreProxies() ([]v1.ProxyConfigurer, error)View on GitHub (pinned to 6c8a8d0a97)
Solutions
- GET the name first and use PUT (update) instead of POST when it already exists
- Pick a unique name — remember file-based and store-based proxies share one namespace per name
- In automation, treat errors.Is(err, configmgmt.ErrConflict) as 'already applied' or follow up with an update
- Remove the duplicate from the config file before creating it via the API
Example fix
// before
_, err := mgr.CreateProxy(ctx, cfg) // conflict: already exists
// after
if _, err := mgr.GetProxy(ctx, cfg.GetBaseConfig().Name); err != nil {
_, err = mgr.CreateProxy(ctx, cfg)
} else {
err = mgr.UpdateProxy(ctx, cfg.GetBaseConfig().Name, cfg)
} Defensive patterns
Strategy: validation
Validate before calling
if _, err := mgr.GetProxy(ctx, cfg.GetBaseConfig().Name); err == nil {
// exists -> update path, avoid Create conflict
} else if !errors.Is(err, configmgmt.ErrNotFound) {
return err
} Try / catch
if _, err := mgr.CreateProxy(ctx, cfg); err != nil {
if errors.Is(err, configmgmt.ErrConflict) {
return mgr.UpdateProxy(ctx, cfg.GetBaseConfig().Name, cfg)
}
return err
} Prevention
- Check-then-create (or upsert) in scripts that run repeatedly
- Namespace generated proxy names (e.g. host+service) to avoid collisions
- Treat 409 as 'already applied' in idempotent automation
When it happens
Trigger: POST /api/proxy or /api/visitor with a name that already exists in the store source or collides with a same-named entry merged from the config file (the aggregator dedupes by name, so creation of a duplicate is rejected).
Common situations: Re-running an automation script that creates proxies without checking existence first; a proxy defined in frpc.toml sharing a name with one being added via the API; retrying a create after a timeout when the first attempt actually succeeded.
Related errors
- ErrInvalidArgument
- ErrNotFound
- ErrStoreDisabled
- ErrAlreadyExists
- invalid argument: frpc has no config file path
AI-assisted analysis of fatedier/frp@6c8a8d0a97 (2026-08-15).
Data as JSON: /api/errors/073f7df2f54fea63.
Report an issue: GitHub.