AdguardTeam/AdGuardHome · error

parsing expiry time: %w

Error message

parsing expiry time: %w

What it means

A stored dynamic lease's Expiry field is not a valid RFC3339 timestamp, so it cannot be converted to time.Time. Static leases are exempt (expiry skipped when IsStatic is true).

Source

Thrown at internal/dhcpd/db.go:79

		Hostname: l.Hostname,
		HWAddr:   l.HWAddr.String(),
		IP:       l.IP,
		IsStatic: l.IsStatic,
	}
}

// toLease converts *dbLease to *dhcpsvc.Lease.
func (dl *dbLease) toLease() (l *dhcpsvc.Lease, err error) {
	mac, err := net.ParseMAC(dl.HWAddr)
	if err != nil {
		return nil, fmt.Errorf("parsing hardware address: %w", err)
	}

	expiry := time.Time{}
	if !dl.IsStatic {
		expiry, err = time.Parse(time.RFC3339, dl.Expiry)
		if err != nil {
			return nil, fmt.Errorf("parsing expiry time: %w", err)
		}
	}

	return &dhcpsvc.Lease{
		Expiry:   expiry,
		IP:       dl.IP,
		Hostname: dl.Hostname,
		HWAddr:   mac,
		IsStatic: dl.IsStatic,
	}, nil
}

// dbLoad loads stored leases.
func (s *server) dbLoad() (err error) {
	data, err := os.ReadFile(s.conf.dbFilePath)
	if err != nil {
		if !errors.Is(err, os.ErrNotExist) {
			return fmt.Errorf("reading db: %w", err)

View on GitHub (pinned to b41aefbe51)

Solutions

  1. Fix expiry values to RFC3339 format with timezone (2026-01-02T15:04:05Z)
  2. Remove the leases file to force re-learning of dynamic leases
  3. Check for and fix truncated/corrupted files

Example fix

// before
{"Expiry": "2026-01-02 15:04:05"}
// after
{"Expiry": "2026-01-02T15:04:05Z"}
Defensive patterns

Strategy: validation

Validate before calling

if !dl.IsStatic {
    if _, err := time.Parse(time.RFC3339, dl.Expiry); err != nil { /* drop lease */ }
}

Type guard

func isRFC3339(s string) bool { _, err := time.Parse(time.RFC3339, s); return err == nil }

Prevention

When it happens

Trigger: Loading the lease DB where a non-static lease has an empty, truncated, or non-RFC3339 Expiry string (e.g. missing timezone offset).

Common situations: Hand-edited lease files, corruption, or a version change in date format; expiry set to 0 or unix epoch integer instead of RFC3339.

Related errors


AI-assisted analysis of AdguardTeam/AdGuardHome@b41aefbe51 (2026-08-27). Data as JSON: /api/errors/88f0f36af0c4b819. Report an issue: GitHub.