OpenNHP/opennhp · error
json parsing error
Error message
json parsing error: %s
What it means
ReadZdtoConfig read `etc/ztdo/data-<doId>.json` but json.Unmarshal could not parse its bytes into common.DRGMsg. The on-disk ZTDO config is malformed or its schema doesn't match DRGMsg fields, so the data-object config is unusable.
Solutions
- Validate the file with a JSON linter / `jq . data-<doId>.json` and fix the syntax error it reports.
- Compare the file's fields against the current common.DRGMsg struct and update the config to the current schema.
- Delete the corrupt file and re-publish the ZTDO through the DHP DRG flow to regenerate it.
- Restore the file from backup if it was truncated by a failed write.
Example fix
// before: hand-edited file with trailing comma
{"doId": "abc", "accessUrl": "https://x",}
// after: valid JSON matching DRGMsg
{"doId": "abc", "accessUrl": "https://x"} Defensive patterns
Strategy: validation
Validate before calling
p := filepath.Join(exeDir, "etc", "ztdo", "data-"+doId+".json")
b, err := os.ReadFile(p)
if err != nil { return err }
if !json.Valid(b) {
return fmt.Errorf("%s is not valid JSON", p)
}
var probe map[string]any
if err := json.Unmarshal(b, &probe); err != nil { return err } Type guard
func isValidZtdoConfig(p string) bool {
b, err := os.ReadFile(p)
if err != nil { return false }
var m common.DRGMsg
return json.Unmarshal(b, &m) == nil
} Try / catch
msg, err := ReadZdtoConfig(doId)
if err != nil && strings.Contains(err.Error(), "json parsing error") {
log.Warn("corrupt ztdo config %s: %v — re-publishing", doId, err)
os.Remove(filepath.Join(ExeDirPath, "etc", "ztdo", "data-"+doId+".json"))
return republishZtdo(doId)
} Prevention
- Never hand-edit data-*.json; always go through the DRG publish flow.
- Run `jq .` validation after any out-of-band config restore.
- Write configs atomically (temp file + rename) to avoid truncation on crash.
When it happens
Trigger: HandleDHPDARMessage/HandleDHPDAVMessage/SaveZdtoConfig load a config file that was hand-edited, truncated by a crashed write, produced by a different (incompatible) schema version, or contains invalid JSON characters.
Common situations: Manual edits to data-*.json introducing syntax errors; server upgrade changed common.DRGMsg field types so old configs no longer unmarshal; disk-full partially wrote the file.
Understand the failure class
Background: JSON parse error: "Unexpected token" / "not valid JSON" / "failed to parse" — what JSON parsers are really complaining about — this error's family across 45 libraries.
Related errors
- json parsing error
- failed to unmarshal evidence
- failed to unmarshal JSON
- unknown remote provider
- unknown remote provider
AI-assisted analysis of OpenNHP/opennhp@6e04ca5ff0 (2026-09-07).
Data as JSON: /api/errors/c79abf59a27db291.
Report an issue: GitHub.
Appendix: source
Thrown at endpoints/server/msghandler.go:768
func ReadZdtoConfig(doId string) (common.DRGMsg, error) {
etcDir := filepath.Join(ExeDirPath, "etc", "ztdo")
configFilePath := filepath.Join(etcDir, "data-"+doId+".json")
file, err := os.Open(configFilePath)
if err != nil {
return common.DRGMsg{}, fmt.Errorf("could not open file: %v", err)
}
defer file.Close()
fileContentByte, err := io.ReadAll(file)
if err != nil {
return common.DRGMsg{}, fmt.Errorf("error reading file: %v", err)
}
var config common.DRGMsg
err = json.Unmarshal(fileContentByte, &config)
if err != nil {
return common.DRGMsg{}, fmt.Errorf("json parsing error: %s", err)
}
return config, nil
}
// HandleRelayForward processes a decrypted NHP_RLY message from the standard
// Noise pipeline. The relay's identity has already been validated by
// validatePeer as part of the standard decryption flow.
//
// The message body is a JSON-encoded RelayForwardMsg containing:
// - SourceAddr: the real client's IP/port
// - InnerPacket: base64-encoded inner NHP packet (encrypted by agent)
//
// The inner packet is injected into the standard pipeline as if the agent
// had connected directly.
func (s *UdpServer) HandleRelayForward(ppd *core.PacketParserData) error {
var rlyMsg common.RelayForwardMsg
if err := json.Unmarshal(ppd.BodyMessage, &rlyMsg); err != nil {
log.Error("server-relay[HandleRelayForward] failed to parse RelayForwardMsg: %v", err)View on GitHub (pinned to 6e04ca5ff0)