{"record":{"id":"591c44e0bc491569","repo":"AdguardTeam/AdGuardHome","slug":"json-duration-is-nil","errorCode":null,"errorMessage":"json duration is nil","messagePattern":"json duration is nil","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/aghhttp/json.go","lineNumber":43,"sourceCode":"// type check\nvar _ json.Marshaler = JSONDuration(0)\n\n// MarshalJSON implements the json.Marshaler interface for JSONDuration.  err is\n// always nil.\nfunc (d JSONDuration) MarshalJSON() (b []byte, err error) {\n\tmsec := float64(time.Duration(d)) / nsecPerMsec\n\tb = strconv.AppendFloat(nil, msec, 'f', -1, 64)\n\n\treturn b, nil\n}\n\n// type check\nvar _ json.Unmarshaler = (*JSONDuration)(nil)\n\n// UnmarshalJSON implements the json.Marshaler interface for *JSONDuration.\nfunc (d *JSONDuration) UnmarshalJSON(b []byte) (err error) {\n\tif d == nil {\n\t\treturn fmt.Errorf(\"json duration is nil\")\n\t}\n\n\tmsec, err := strconv.ParseFloat(string(b), 64)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"parsing json time: %w\", err)\n\t}\n\n\t*d = JSONDuration(int64(msec * nsecPerMsec))\n\n\treturn nil\n}\n\n// JSONTime is a time.Time that can be decoded from JSON and encoded into JSON\n// according to our API conventions.\ntype JSONTime time.Time\n\n// type check\nvar _ json.Marshaler = JSONTime{}","sourceCodeStart":25,"sourceCodeEnd":61,"githubUrl":"https://github.com/AdguardTeam/AdGuardHome/blob/b41aefbe51c8dde65e2c50f093996afa0502edf9/internal/aghhttp/json.go#L25-L61","documentation":"updConfMgr constructs a fresh configuration manager with configmgr.New(ctx, s.confMgrConf); if construction fails the error is wrapped as 'creating config manager'. This is the underlying cause surfaced by Refresh's 'updating configuration manager' error and points at config loading/validation problems rather than service startup.","triggerScenarios":"Calling Refresh (which calls updConfMgr) when configmgr.New fails: unreadable/missing config file, schema-invalid YAML, or an environment (working directory, env vars) that makes config discovery fail.","commonSituations":"Config file deleted or renamed while the service runs; config contains keys removed in a newer version; the process's working directory changed so relative config paths break.","solutions":["Look at the wrapped error from configmgr.New for the specific file/key at fault","Validate the config file against the current version's schema (check docs/changelog for removed keys)","Ensure the config path passed in confMgrConf exists and is readable by the service user","Recreate or restore the config file from backup"],"exampleFix":null,"handlingStrategy":"validation","validationCode":"// Ensure config file is readable and parses before Refresh\nif _, err := os.Stat(confPath); err != nil { return err }\nif data, err := os.ReadFile(confPath); err != nil { return err } else if !yaml.IsV3Compatible(data) { /* validate */ }","typeGuard":null,"tryCatchPattern":"if err := srv.updConfMgr(ctx); err != nil {\n    return fmt.Errorf(\"config manager rebuild failed: %w\", errors.Unwrap(err))\n}","preventionTips":["Validate config schema on every deploy","Use absolute config paths","Restrict write access to the config to known tooling"],"tags":["config","config-manager","refresh","go"],"backgroundTag":"config-load-failed","analyzedSha":"b41aefbe51c8dde65e2c50f093996afa0502edf9","analyzedAt":"2026-08-27T04:57:55.097Z","schemaVersion":2},"datasetVersion":"2026-08-27T08:17:20.692Z"}