fix: recognize CloudAMQP's duplicate-invite 400 as already-invited - #19
Conversation
CreateAccount's retry path only treated HTTP 409 as already-exists, but CloudAMQP's POST /team/invite never returns 409 — a duplicate invite and a malformed email both come back as 400, distinguished only by the JSON error body. The client now captures that body so IsAlreadyInvitedError can match on "User is already invited" specifically, letting a re-driven provisioning retry land on the existing ActionRequiredResult path instead of hard-failing. Fixes CXH-2233. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
| } | ||
| }) | ||
| } | ||
| } |
There was a problem hiding this comment.
🟡 Suggestion: The new unit tests cover the helpers well, but the mock in cmd/test-server/main.go still auto-accepts invites and returns 409 on duplicates (store.invite), so no end-to-end test exercises the 400 + {"error":"User is already invited"} shape that this PR exists to handle. Adding a pending-invite state to the mock that answers a re-invite with that 400 body would cover the CreateAccount → ActionRequiredResult path this fix relies on. (Confidence: high that the gap exists; non-blocking.)
Connector PR Review: fix: recognize CloudAMQP's duplicate-invite 400 as already-invitedBlocking Issues: 0 | Suggestions: 0 | Threads Resolved: 0 Review SummaryScanned the full PR diff ( The third prior finding is still open and is not re-flagged as new: Security IssuesNone found. Correctness IssuesNone found. SuggestionsNone. Note: the machine-readable review-state marker could not be written this run because the sandbox rejects the shell syntax required to emit it; the next review will run in full mode. |
- Give the //nolint:gosec in helpers_test.go an explanation (nolintlint was failing CI). - Bound newAPIError's body read with io.LimitReader instead of an unbounded io.ReadAll. - Extract the "already invited" match string into a const. - Fix the now-stale "after 409" wording in CreateAccount's re-resolve error, since that branch is also reached via the new HTTP 400 path. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Summary
CreateAccount's retry path only treated HTTP 409 as already-exists, but CloudAMQP'sPOST /team/invitenever returns 409 — a duplicate invite and a malformed email both come back as HTTP 400, distinguishable only by the JSON error body."User is already invited","Invalid email") instead of discarding it.cloudamqp.IsAlreadyInvitedError, which matches HTTP 400 + a message containing "already invited", and wired it intoCreateAccount's invite-error handling alongside the existing 409 check.This lets a re-driven provisioning task (the C1 retry after the invitee hasn't yet accepted the first invite) land on the existing "invitation already pending"
ActionRequiredResultpath instead of hard-failing the task.Fixes CXH-2233.
Note: the exact vendor message string (
"User is already invited") is sourced from the ticket's live-API reproduction, not from CloudAMQP's published docs — if the wording ever changes on their end, this match will need to be revisited.Test plan
go build ./...go test ./... -count=1(21 tests passing, including newpkg/cloudamqp/helpers_test.gocases fornewAPIErrorandIsAlreadyInvitedError)🤖 Generated with Claude Code