fatedier/frp · error
no sources configured
Error message
no sources configured
What it means
Aggregator.Load (pkg/config/source/aggregator.go:76) refuses to load when getSourcesLocked returns zero sources. The aggregator merges a config file source and an optional store source; a zero-value Aggregator (struct created without NewAggregator) has both fields nil, hence no sources. NewAggregator itself always installs a config source, so in practice this error means the aggregator was constructed incorrectly rather than configured empty.
Source
Thrown at pkg/config/source/aggregator.go:76
func (a *Aggregator) getSourcesLocked() []Source {
sources := make([]Source, 0, 2)
if a.configSource != nil {
sources = append(sources, a.configSource)
}
if a.storeSource != nil {
sources = append(sources, a.storeSource)
}
return sources
}
func (a *Aggregator) Load() ([]v1.ProxyConfigurer, []v1.VisitorConfigurer, error) {
a.mu.RLock()
entries := a.getSourcesLocked()
a.mu.RUnlock()
if len(entries) == 0 {
return nil, nil, errors.New("no sources configured")
}
proxyMap := make(map[string]v1.ProxyConfigurer)
visitorMap := make(map[string]v1.VisitorConfigurer)
for _, src := range entries {
proxies, visitors, err := src.Load()
if err != nil {
return nil, nil, fmt.Errorf("load source: %w", err)
}
for _, p := range proxies {
proxyMap[p.GetBaseConfig().Name] = p
}
for _, v := range visitors {
visitorMap[v.GetBaseConfig().Name] = v
}
}
proxies, visitors := a.mapsToSortedSlices(proxyMap, visitorMap)View on GitHub (pinned to 6c8a8d0a97)
Solutions
- Construct with source.NewAggregator(cfgSource) (a nil argument is fine — it creates a default ConfigSource)
- Or call SetStoreSource / ensure a config source is attached before Load
- Treat this error as a programming bug in the caller, not a runtime condition to retry
- Add a unit test asserting Load works right after NewAggregator
Example fix
// before
agg := &source.Aggregator{}
_, _, err := agg.Load() // no sources configured
// after
agg := source.NewAggregator(nil)
_, _, err := agg.Load() Defensive patterns
Strategy: validation
Validate before calling
// Never use a zero-value aggregator var agg *source.Aggregator // unsafe if Load() called agg := source.NewAggregator(nil) // always has >= 1 source
Try / catch
proxies, visitors, err := agg.Load()
if err != nil && strings.Contains(err.Error(), "no sources configured") {
// construction bug — fix caller, do not retry
return fmt.Errorf("aggregator misuse: construct with NewAggregator: %w", err)
} Prevention
- Always construct via NewAggregator; forbid struct literals in review
- Add a lint/test that Load() succeeds immediately after construction
- Attach the store source with SetStoreSource as soon as it is created
When it happens
Trigger: Using `var agg source.Aggregator` or `&source.Aggregator{}` directly and calling Load(); NewAggregator always returns an aggregator with a non-nil configSource, so library consumers bypassing the constructor are the real trigger.
Common situations: Embedding frp's config source package in another tool and instantiating the struct literal instead of NewAggregator; refactoring that drops the constructor call.
Related errors
- ErrAlreadyExists
- exec configuration is required when type is 'exec'
- file path cannot be empty
- exec command cannot be empty
- exec env name cannot be empty
AI-assisted analysis of fatedier/frp@6c8a8d0a97 (2026-08-15).
Data as JSON: /api/errors/66954c59fc994292.
Report an issue: GitHub.