AdguardTeam/AdGuardHome · error
json time is nil
Error message
json time is nil
What it means
The DNS PATCH handler successfully decoded the request and applied the requested fields to a copy of the current DNS config, but confMgr.UpdateDNS rejected the resulting configuration. The wrapped error describes which DNS setting was invalid (upstream servers, bootstrap DNS, listening addresses, etc.).
Solutions
- Read the wrapped error from UpdateDNS — it names the offending field/value
- Fix the specific DNS setting (upstream URL format, listen address syntax) and retry the PATCH
- GET the current DNS config first, validate the merged result locally, then PATCH
- Consult the DNS configuration docs for accepted upstream URL formats
Example fix
// before
{"upstream_dns": ["8.8.8.8"]}
// after
{"upstream_dns": ["8.8.8.8:53"]} // or "https://dns.google/dns-query" Defensive patterns
Strategy: validation
Validate before calling
// GET current config, merge, validate upstream formats client-side
if !validUpstreamURL(u) { return fmt.Errorf("bad upstream %q", u) } Type guard
func validUpstreamURL(s string) bool {
_, err := url.Parse(s)
return err == nil && (strings.Contains(s, "://") || net.ParseIP(s) != nil || isHostPort(s))
} Try / catch
if err := updateDNS(cfg); err != nil {
if strings.Contains(err.Error(), "updating:") {
// field-level validation issue; fix named field and retry
}
} Prevention
- Fetch and merge current config before PATCHing
- Follow documented upstream DNS URL formats
- Dry-run validation of DNS settings in the UI first
When it happens
Trigger: PATCHing DNS settings where the merged configuration is invalid: malformed upstream DNS URLs, invalid listen addresses, bad bootstrap values, or an invalid upstream mode.
Common situations: Typo in an upstream DNS server URL (missing dns:// scheme or port); setting an empty upstream list; combining incompatible DNS options; a partial PATCH interacting badly with existing config values.
Understand the failure class
Background: "Invalid value" and "allowed values are" config errors: what your library rejected and how to fix it — this error's family across 41 libraries.
Related errors
AI-assisted analysis of AdguardTeam/AdGuardHome@b41aefbe51 (2026-08-27).
Data as JSON: /api/errors/f60fd868fd46d631.
Report an issue: GitHub.
Appendix: source
Thrown at internal/aghhttp/json.go:78
// type check
var _ json.Marshaler = JSONTime{}
// MarshalJSON implements the json.Marshaler interface for JSONTime. err is
// always nil.
func (t JSONTime) MarshalJSON() (b []byte, err error) {
msec := float64(time.Time(t).UnixNano()) / nsecPerMsec
b = strconv.AppendFloat(nil, msec, 'f', -1, 64)
return b, nil
}
// type check
var _ json.Unmarshaler = (*JSONTime)(nil)
// UnmarshalJSON implements the json.Marshaler interface for *JSONTime.
func (t *JSONTime) UnmarshalJSON(b []byte) (err error) {
if t == nil {
return fmt.Errorf("json time is nil")
}
msec, err := strconv.ParseFloat(string(b), 64)
if err != nil {
return fmt.Errorf("parsing json time: %w", err)
}
*t = JSONTime(time.Unix(0, int64(msec*nsecPerMsec)).UTC())
return nil
}
// WriteJSONResponse writes headers with the code, encodes resp into w, and logs
// any errors it encounters. r is used to get additional information from the
// request. l, w, and r must not be nil.
func WriteJSONResponse(
ctx context.Context,
l *slog.Logger,View on GitHub (pinned to b41aefbe51)