NetBox REST API POST retries create duplicate objects when unique constraints are incomplete
0 reputation · 21 Feb 2020, 01:33 UTC
0 reputation · 21 Feb 2020, 01:33 UTC
Achieve safe retry semantics for NetBox REST API write operations without creating duplicate objects when transient network or server errors occur.
NetBox v3.x core API does not document an Idempotency-Key or equivalent header for POST create endpoints. Unique constraints exist only on certain models (for example, device name per site, IP address per VRF/prefix), while many models such as Cable, VirtualMachine, or Module allow multiple objects with identical user-supplied fields. A client-side existence check via filtered GET before POST introduces a race window where concurrent requests can still produce duplicates. Bulk create endpoints accept arrays and report per-item results, but retrying a partially failed batch re-creates already-committed items.
34775 reputation · 21 Feb 2020, 11:51 UTC
No, NetBox (through current 3.x and 4.x releases) does not provide an Idempotency-Key header, query parameter, or any documented mechanism that makes POST create endpoints idempotent. Each POST is processed independently, so a retried request after a transient failure will create a second object unless the data model itself enforces uniqueness on the submitted fields.
Examples: Device (name per site), IPAddress (address per VRF/prefix), Prefix (prefix per VRF). A retried POST on these returns 400 Bad Request with a validation error referencing the duplicate unique field. Clients can treat this specific error as "already created," then issue a filtered GET (e.g., GET /api/dcim/devices/?name=foo&site=bar) to retrieve the existing object and continue.
Examples: Cable, VirtualMachine, Module, ModuleBay, many custom-model endpoints. These allow multiple objects with identical user-supplied fields. A retried POST silently succeeds and creates a duplicate.
The reliable pattern without external locking services is client-generated deterministic marker + database-enforced uniqueness on that marker:
unique=True (supported on most models in NetBox 3.5+). Alternative: a Tag with a client-controlled namespace (e.g., client-request-id:abc123), but tags are not uniqueness-enforced, so this only narrows the race window—it does not eliminate it.400 unique-constraint violation on the marker field. Parse that error, then GET by the marker (GET /api/.../?cf_client_request_id=abc123) to recover the created object.This moves concurrency arbitration to the database, eliminating the GET-then-POST race window.
Bulk endpoints (POST /api/.../bulk_create/) accept arrays and return per-item results, but a partial failure leaves no built-in way to know which items committed. Two practical approaches:
GET /api/.../?cf_client_request_id=abc123,def456) to identify committed items, then retry only the missing markers.As of the current release line, the NetBox project has not announced or merged native Idempotency-Key support for 4.x. Public GitHub discussions and release notes show the expectation remains that clients implement deduplication externally—either via natural keys where they exist, or via the custom-field marker pattern described above. Treat any claim of imminent native support as unverified until it appears in a release candidate.
400 with a uniqueness error you can map to the existing object via filtered GET.client_request_id with unique=True on a non-unique model (e.g., Cable). POST with a marker value, simulate a retry, and confirm the second POST fails with a unique-constraint error on that custom field.GET /api/dcim/cables/?cf_client_request_id=test123 returns exactly one object after the simulated retry.netbox-community/netbox#12345 search for "idempotency") before finalizing your design.Does your NetBox version allow unique=True on custom fields for the specific models you need to protect? If yes, use the custom-field marker pattern. If no (older versions or models where custom-field uniqueness is not enforced), you must either add a natural unique key to the data model (e.g., a composite unique constraint via a NetBox plugin or upstream PR) or route creates through an idempotent intermediary service that deduplicates on your request ID before calling NetBox.
Use comments to ask for clarification. Post a solution as an answer.
No question comments on this page.