Skip to content

UNIFI: fix errors on version 10.2.105#4201

Open
Matthew-Kilpatrick wants to merge 1 commit intoDNSControl:mainfrom
Matthew-Kilpatrick:copilot/fix-unifi-provider-error
Open

UNIFI: fix errors on version 10.2.105#4201
Matthew-Kilpatrick wants to merge 1 commit intoDNSControl:mainfrom
Matthew-Kilpatrick:copilot/fix-unifi-provider-error

Conversation

@Matthew-Kilpatrick
Copy link
Copy Markdown

@Matthew-Kilpatrick Matthew-Kilpatrick commented Apr 18, 2026

When using the Unifi provider with Unifi Network 10.2.105, a number of errors cause DNSControl to fail to apply changes.

Metadata in payload

FAILURE! failed to create record: [UNIFI] POST /integration/v1/sites/88f7af54-98f8-306a-a1c7-c9349722b1f6/dns/policies -> 400: {"statusCode":400,"statusName":"BAD_REQUEST","code":"api.request.unknown-property","message":"Unknown request body property '$.metadata'","timestamp":"2026-04-18T20:41:19.600263489Z","requestPath":"/integration/v1/sites/88f7af54-98f8-306a-a1c7-c9349722b1f6/dns/policies","requestId":"f9cceb4c-4e6d-4119-a6a6-e29fa2211b40"}

Looking over the documentation at https://developer.ui.com/network/v10.1.84/creatednspolicy, it seems the metadata field this provider was attempting to write to is documented as read-only.

This PR updates the provider to no longer set the metadata field when making requests to the API:

#3: + CREATE auth.domain.uk A 10.1.1.2 ttl=1
[UNIFI] [DEBUG] POST https://10.1.1.1/proxy/network/integration/v1/sites/88f7af54-98f8-306a-a1c7-c9349722b1f6/dns/policies
Payload: {"type":"A_RECORD","enabled":true,"domain":"auth.domain.uk","ttlSeconds":1,"ipv4Address":"10.1.1.2"}
[UNIFI] [DEBUG] Response (201): {"type":"A_RECORD","id":"a9238946-8cbe-4be5-b65e-1b5106e049c9","enabled":true,"metadata":{"origin":"USER_DEFINED"},"domain":"auth.domain.uk","ipv4Address":"10.1.1.2","ttlSeconds":1}
SUCCESS!

ID in payload

The ID was provided in the path (as expected), but also the request payload, which Unifi's validation did not like.

Payload: {"type":"A_RECORD","id":"e90619e0-3bce-46b3-a79e-27440ca3bb58","enabled":true,"domain":"auth.domain.uk","ipv4Address":"10.1.1.2"}
[UNIFI] [DEBUG] Response (400): {"statusCode":400,"statusName":"BAD_REQUEST","code":"api.request.unknown-property","message":"Unknown request body property '$.id'","timestamp":"2026-04-22T18:13:30.314225148Z","requestPath":"/integration/v1/sites/88f7af54-98f8-306a-a1c7-c9349722b1f6/dns/policies/e90619e0-3bce-46b3-a79e-27440ca3bb58","requestId":"003508a3-1da7-47a8-9b16-7faba232fa66"}

Omitted TTL

The documentation on the Unifi site doesn't list this field as required so I'm somewhat confused by this, however, the provider omitted this field for a value of 300s, and this resulted in the following error:

[UNIFI] [DEBUG] POST https://10.1.1.1/proxy/network/integration/v1/sites/88f7af54-98f8-306a-a1c7-c9349722b1f6/dns/policies
Payload: {"type":"A_RECORD","enabled":true,"domain":"auth.domain.uk","ipv4Address":"10.1.1.2"}
[UNIFI] [DEBUG] Response (400): {"statusCode":400,"statusName":"BAD_REQUEST","code":"api.request.error","message":"ttlSeconds must not be null","timestamp":"2026-04-22T18:13:30.393200035Z","requestPath":"/integration/v1/sites/88f7af54-98f8-306a-a1c7-c9349722b1f6/dns/policies","requestId":"327b03ae-7793-476b-bedf-353c6d30bd64"}

I don't see any harm including it even if it matches the default (if anything, I think it's a marginal improvement - in the event unifi changed defaults, the config from DNSControl should be the source of truth).

Record pagination

When checking existing DNS record state, the existing implementation made a single call to GET /v1/sites/{siteId}/dns/policies`. This had a default limit of 25 records, so could cause errors when re-creating existing records:

[UNIFI] [DEBUG] POST https://10.1.1.1/proxy/network/integration/v1/sites/88f7af54-98f8-306a-a1c7-c9349722b1f6/dns/policies
Payload: {"type":"A_RECORD","enabled":true,"domain":"auth.domain.uk","ttlSeconds":300,"ipv4Address":"10.1.1.2"}
[UNIFI] [DEBUG] Response (400): {"statusCode":400,"statusName":"BAD_REQUEST","code":"api.dns.policy.validation.record-already-exists","message":"DNS policy with the same type and properties already exists","timestamp":"2026-04-22T18:36:29.445574077Z","requestPath":"/integration/v1/sites/88f7af54-98f8-306a-a1c7-c9349722b1f6/dns/policies","requestId":"f45e7ecf-ae97-468b-9be2-1fee036c380b"}
FAILURE! failed to create record: [UNIFI] POST /integration/v1/sites/88f7af54-98f8-306a-a1c7-c9349722b1f6/dns/policies -> 400: {"statusCode":400,"statusName":"BAD_REQUEST","code":"api.dns.policy.validation.record-already-exists","message":"DNS policy with the same type and properties already exists","timestamp":"2026-04-22T18:36:29.445574077Z","requestPath":"/integration/v1/sites/88f7af54-98f8-306a-a1c7-c9349722b1f6/dns/policies","requestId":"f45e7ecf-ae97-468b-9be2-1fee036c380b"}

I've updated this to paginate results to ensure all records are fetched.

@Matthew-Kilpatrick Matthew-Kilpatrick changed the title Unifi provider: fix Unknown request body property '$.metadata' error UNIFI: fix Unknown request body property '$.metadata' error Apr 18, 2026
@TomOnTime
Copy link
Copy Markdown
Collaborator

Thank you for sending this!

Right now the project is in transition but I hope to be able to address this once we've moved to our new git org.

@Matthew-Kilpatrick Matthew-Kilpatrick force-pushed the copilot/fix-unifi-provider-error branch from c2eec88 to 0439ce6 Compare April 22, 2026 18:28
@Matthew-Kilpatrick Matthew-Kilpatrick changed the title UNIFI: fix Unknown request body property '$.metadata' error UNIFI: fix errors on version 10.2.105 Apr 22, 2026
A number of issues with request payloads resulted in errors from some
Unifi Network versions (eg. 10.2.105), which this commit addresses:

- The `metadata` field is documented as read-only, and so when this
  provider included this field in the request payload, the error
  `Unknown request body property '$.metadata' was returned
- The `id` being passed in payloads for updates caused issues
  (`Unknown request body property '$.id'`), as this is an undocumented
  field which is provided in the path.
- The omission of the `ttlSeconds` field (which was the case for the
  default 300 value) resulted in `ttlSeconds must not be null`
- The provider previously made a single `GET `/v1/sites/{siteId}/dns/policies`
  request to check the current state, however, a default page-size limit of 25
  records and lack of pagination could miss records and result in
  `DNS policy with the same type and properties already exists` errors
@Matthew-Kilpatrick Matthew-Kilpatrick force-pushed the copilot/fix-unifi-provider-error branch from 7ad1941 to 61eaa0a Compare April 22, 2026 20:11
@zupolgec
Copy link
Copy Markdown
Contributor

Thanks @Matthew-Kilpatrick for tracking this down and writing it up so cleanly, the reproduction logs in the description made it trivial to verify.

I ran the current main and this PR side-by-side against my own UniFi Network v10.2.105 controller (via the new API) and can confirm:

  • Current: POST /dns/policies fails with the exact same api.request.unknown-property / $.metadata 400 you captured.
  • This PR: full CREATE → UPDATE → DELETE cycle succeeds (ttl 300 record), and the paginated GET /dns/policies?offset=0&limit=200 returns every record instead of being silently capped at 25.

All four server-side changes you pinned down line up with what I see on v10.2.105: unknown-property rejection is now strict, ttlSeconds is required/non-null, and id is path-only for PUT.

Nice work, and thanks again

I really love open source! 😀

@TomOnTime
Copy link
Copy Markdown
Collaborator

Thank you for sending this!

Right now the project is in transition but I hope to be able to address this once we've moved to our new git org.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

3 participants