fatedier/frp · error
failed to parse JSON: %w
Error message
failed to parse JSON: %w
What it means
loadFromFileUnlocked read the store file successfully but its contents are not valid JSON, so jsonx.Unmarshal into the raw {proxies, visitors} envelope failed. The store file must be a JSON object whose proxies/visitors members are arrays; any syntax error anywhere in the file produces this error.
Source
Thrown at pkg/config/source/store.go:88
func (s *StoreSource) loadFromFile() error {
s.mu.Lock()
defer s.mu.Unlock()
return s.loadFromFileUnlocked()
}
func (s *StoreSource) loadFromFileUnlocked() error {
data, err := os.ReadFile(s.config.Path)
if err != nil {
return err
}
type rawStoreData struct {
Proxies []jsonx.RawMessage `json:"proxies,omitempty"`
Visitors []jsonx.RawMessage `json:"visitors,omitempty"`
}
stored := rawStoreData{}
if err := jsonx.Unmarshal(data, &stored); err != nil {
return fmt.Errorf("failed to parse JSON: %w", err)
}
s.proxies = make(map[string]v1.ProxyConfigurer)
s.visitors = make(map[string]v1.VisitorConfigurer)
for i, proxyData := range stored.Proxies {
proxyCfg, err := v1.DecodeProxyConfigurerJSON(proxyData, v1.DecodeOptions{
DisallowUnknownFields: false,
})
if err != nil {
return fmt.Errorf("failed to decode proxy at index %d: %w", i, err)
}
name := proxyCfg.GetBaseConfig().Name
if name == "" {
return fmt.Errorf("proxy name cannot be empty")
}
s.proxies[name] = proxyCfg
}View on GitHub (pinned to 6c8a8d0a97)
Solutions
- Validate the file offline: jq . <path> — jq pinpoints the line/column of the syntax error
- Fix the reported syntax issue (trailing comma, missing quote, comment) and retry NewStoreSource
- If the file is unusable, restore it from backup or VCS history (git checkout -- store.json)
- As a last resort, move the file aside (mv store.json store.json.bak) to start with an empty store, then re-add proxies/visitors through the API
Example fix
// before: file content
{ "proxies": [ {"type":"tcp","name":"web"}, ], }
// after: valid JSON
{ "proxies": [ {"type":"tcp","name":"web"} ] } Defensive patterns
Strategy: validation
Validate before calling
func validateStoreJSON(path string) error {
data, err := os.ReadFile(path)
if errors.Is(err, fs.ErrNotExist) {
return nil
}
if err != nil {
return err
}
if !json.Valid(data) {
return fmt.Errorf("store file %s is not valid JSON", path)
}
return nil
} Try / catch
src, err := source.NewStoreSource(cfg)
if err != nil && strings.Contains(err.Error(), "failed to parse JSON") {
// quarantine the bad file and start empty (accepting data loss) or restore from backup
_ = os.Rename(cfg.Path, cfg.Path+".corrupt")
} Prevention
- Never hand-edit the generated store file; use the Add/Update/Remove API
- If the file is under VCS, run a pre-commit hook with jq . to catch syntax errors
- Back up the store before upgrades that change its format
When it happens
Trigger: The store file was hand-edited and contains a trailing comma, unquoted key, or comment; the file was truncated by an external process (this library itself writes atomically via temp-file + rename, so self-inflicted truncation is unlikely); an empty (0-byte) file also fails JSON parsing; a file with a UTF-8 BOM or C2 A0 characters pasted from a rich-text editor.
Common situations: Manually tweaking the generated store JSON instead of using the API; a git merge conflict resolved badly on a committed store file; a partially synced/copied file between hosts; running an old frp version that wrote a non-JSON format (e.g. TOML/INI) at the same path.
Understand the failure class
- Parsing and encoding errors: unexpected token, malformed input — why parsers reject input and how to find the real culprit.
Related errors
- line %d: field "%s": cannot unmarshal %s into %s
- field "%s": cannot unmarshal %s into %s
- failed to decode proxy at index %d: %w
- proxy name cannot be empty
- failed to decode visitor at index %d: %w
AI-assisted analysis of fatedier/frp@6c8a8d0a97 (2026-08-15).
Data as JSON: /api/errors/87d7cae3685fb5b7.
Report an issue: GitHub.