go-unifi

Troubleshooting

Common symptoms — TLS failures, version mismatches, JSON decode errors and validation rejections — and how to fix them.

This page collects the failures people hit most often, the symptom you actually see, and the fix. When in doubt, turn the logger up to Trace (see Logging) to watch URL building, interceptors, and decoding.

Connection and TLS

Version mismatches

JSON decode errors

The controller is loose about scalar types: the same field can arrive as a number, a quoted string, an empty string, null, or a word like "auto" / "enabled" depending on firmware. The library smooths this over with custom unmarshalers in unifi/json.go:

  • numberOrString — accepts a JSON number or a string (e.g. a radio channel of 36 or "auto"), and maps ""/null to the empty string.
  • emptyStringInt — accepts an int that the controller sometimes sends as ""; decodes empty/null to 0 and marshals 0 back as "" to round-trip cleanly.
  • booleanishString — tolerates true/false, "enabled"/"disabled", "1"/"0", and empty/null, collapsing them to a bool (used by fields like Device.LtePoe).

These are applied automatically on the affected fields, so you normally never see them. If you do hit an error like json: cannot unmarshal string into Go struct field … of type int, it usually means the controller sent a shape a field doesn't yet tolerate — a sign the generated types have drifted from your firmware. Capture the raw response (a body-logging HttpRoundTripperProvider, see Interceptors) and open an issue with the payload.

Don't read resp.Body inside an InterceptResponse — the body is decoded after interceptors run, and draining it yields a silently zero-valued result. Use an HttpRoundTripperProvider to buffer and restore the body safely.

Validation rejections

In HardValidation mode a write can fail locally before it ever reaches the controller, surfacing a *unifi.ValidationError. The generated validate tags come from the controller's own API definitions and are occasionally stricter than a given firmware actually enforces.

If you're confident a value is valid for your controller, you have two mitigations:

  • Switch to the default SoftValidation — the field is logged as a WARN but the request is still sent.
  • Use DisableValidation to skip validation entirely (last resort):
disable-validation.go
c, err := unifi.NewClient(&unifi.ClientConfig{
	URL:            "https://unifi.example.com",
	APIKey:         "your-api-key",
	ValidationMode: unifi.DisableValidation,
})

See Validation for inspecting ValidationError.Messages and registering custom validators.

Still stuck?

On this page