Capture API: an Idempotency-Key longer than 200 characters answers 500 on PostgreSQL #433
Labels
No labels
accessibility
authentication
breaking change
bug
documentation
enhancement
interface
internationalisation
observability
performance
security
tier
1
tier
2
tier
3
tier/4
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set
Reference
Postulo/postulo#433
Loading…
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Found on 2026-09-29 in a read-only review of postulo at
95348908d, reading the capture call's idempotency handling.Checked again on 2026-10-01 against
mainat0a5cad587: still present. The code is now atapi/api.py:425-433(theIdempotency-Keyheader ofcreate_capture);api/idempotency.pyandapi/models.pyhave not moved.POST /api/v1/capturesaccepts anIdempotency-Keyof any length and stores it in a 200-character column. PostgreSQL refuses the over-long value withDataError, whichidempotency.oncedoes not catch (it catchesIntegrityErroronly), so the request fails as an unhandled 500 before any capture is made. SQLite does not enforcevarcharlengths, so the default install and the SQLite test run never see it.api/api.py:423-431(create_capture,idempotency_key: str | None = Header(None, alias="Idempotency-Key", ...), nomax_length);api/idempotency.py:78-89(once:answer.key = key.strip(), thenIdempotentRequest.objects.create(...)insidetransaction.atomic(),except IntegrityError);api/models.py:183(key = models.CharField(_("key"), max_length=200, editable=False)).docker/compose.postgres.yml,POSTULO_DATABASE_URL=postgres://…) sends a capture with a 201-character key, for example one built from the posting's URL. The insert raisesDataError: value too long for type character varying(200); none of the handlers inapi/problems.pyorapi/api.pycatches it, and the client gets a 500 rather than a problem document. Every retry does the same. The same client works on SQLite. The wiki's The capture API says the key is "any string of your own invention" and names no limit.Header(None, alias="Idempotency-Key", max_length=200, ...). Checked against the installed django-ninja: a 201-character value then answers 422 (avalidation-failedproblem document naming the header) and a 200-character one passes. State the limit in the header's description and in the wiki's Sending the same posting twice paragraph.Done when
tests/test_capture_api.pythat sends a capture with a 201-characterIdempotency-Keygets a 422 naming the header, and one with 200 characters is accepted; it fails today on the SQLite run too, which answers 201.