Skip to content

BCM-3707: add structured CONFLICT error codes - #175

Draft
iljapavlovs wants to merge 3 commits into
mainfrom
feat/BCM-3707-add-conflict-codes
Draft

BCM-3707: add structured CONFLICT error codes#175
iljapavlovs wants to merge 3 commits into
mainfrom
feat/BCM-3707-add-conflict-codes

Conversation

@iljapavlovs

@iljapavlovs iljapavlovs commented Jul 15, 2026

Copy link
Copy Markdown
Contributor

Pull request overview

Adds first-class support in the SDK for structured HTTP 409 (CONFLICT) responses by mapping ApplicationError.code values to stable, shared sentinel errors (so errors.Is works consistently across packages).

Changes:

  • Introduces canonical 409 conflict sentinels plus helpers to map/wrap conflict ApplicationError payloads (apierror.Conflict, apierror.WrapConflict, apierror.ConflictCode).
  • Updates multiple domain clients (channels, wallets, watchers, transact, queries) to explicitly handle HTTP 409 and return typed sentinel errors when a recognized conflict code is present.
  • Adds/updates tests to validate conflict-code mapping behavior in apierror, channels, queries, and transact.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds first-class support in the SDK for structured HTTP 409 (CONFLICT) responses by mapping ApplicationError.code values to stable, shared sentinel errors (so errors.Is works consistently across packages).

Changes:

  • Introduces canonical 409 conflict sentinels plus helpers to map/wrap conflict ApplicationError payloads (apierror.Conflict, apierror.WrapConflict, apierror.ConflictCode).
  • Updates multiple domain clients (channels, wallets, watchers, transact, queries) to explicitly handle HTTP 409 and return typed sentinel errors when a recognized conflict code is present.
  • Adds/updates tests to validate conflict-code mapping behavior in apierror, channels, queries, and transact.

Reviewed changes

Copilot reviewed 11 out of 12 changed files in this pull request and generated 6 comments.

Show a summary per file
File Description
apierror/apierror.go Adds canonical conflict sentinels + mapping/wrapping helpers for HTTP 409 responses.
apierror/apierror_test.go Adds unit tests for conflict mapping, wrapping, and code extraction.
channels/channels.go Handles 409 for create/update and exposes ErrChannelAlreadyExists.
channels/channels_test.go Updates create-conflict tests to use structured conflict payloads; adds missing-code fallback test.
wallets/wallets.go Handles 409 for create/update; exposes wallet-related conflict sentinels.
watchers/watchers.go Handles 409 for create/update/archive; exposes watcher conflict sentinels.
transact/transact.go Handles 409 for create operation and draft finalize/cancel paths with conflict-code awareness.
transact/transact_test.go Adds tests asserting conflict-code mapping is surfaced via errors.Is.
queries/queries.go Adds ErrIdempotencyKeyMismatch and maps 409 to typed conflict sentinel when present.
queries/queries_test.go Adds coverage for idempotency-key-mismatch conflict mapping.
go.mod Bumps crec-api-go dependency to a newer pseudo-version that includes conflict codes.
go.sum Updates checksums for the new crec-api-go version.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread transact/transact.go
Comment on lines 761 to 766
case http.StatusConflict:
if mapped := apierror.Conflict(resp.JSON409); mapped != nil {
return nil, fmt.Errorf("%w: %w", ErrDraftNotFinalizable, mapped)
}
return nil, ErrDraftNotFinalizable
case http.StatusUnauthorized:
Comment thread transact/transact.go Outdated
Comment on lines 830 to 834
case http.StatusConflict:
if mapped := apierror.Conflict(resp.JSON409); mapped != nil {
return fmt.Errorf("%w: %w", ErrDraftNotCancellable, mapped)
}
return ErrDraftNotCancellable
Comment thread transact/transact.go Outdated
Comment on lines +270 to +274
case http.StatusConflict:
c.logger.Warn("Conflict when creating operation",
"channel_id", channelID.String(),
"code", apierror.ConflictCode(resp.JSON409))
return nil, apierror.WrapConflict(resp.JSON409, ErrCreateOperation, "")
Comment thread watchers/watchers.go
Comment on lines +278 to +282
case http.StatusConflict:
c.logger.Warn("Conflict when creating watcher with service",
"channel_id", channelID.String(),
"code", apierror.ConflictCode(resp.JSON409))
return nil, apierror.WrapConflict(resp.JSON409, ErrCreateWatcherService, "channel ID "+channelID.String())
Comment thread wallets/wallets.go
Comment on lines +265 to +269
case http.StatusConflict:
c.logger.Warn("Conflict when creating wallet",
"name", input.Name,
"code", apierror.ConflictCode(resp.JSON409))
return nil, apierror.WrapConflict(resp.JSON409, ErrCreateWallet, "name "+input.Name)
Comment thread channels/channels.go
Comment on lines +324 to +328
case http.StatusConflict:
c.logger.Warn("Conflict when updating channel",
"channel_id", channelID.String(),
"code", apierror.ConflictCode(resp.JSON409))
return nil, apierror.WrapConflict(resp.JSON409, ErrUpdateChannel, "channel ID "+channelID.String())
@iljapavlovs
iljapavlovs requested a review from urielkelman July 16, 2026 12:10
Comment thread transact/transact.go Outdated
ErrOperationDeadlineElapsed = apierror.ErrOperationDeadlineElapsed
// ErrResourceVersionConflict is returned when an operation was modified concurrently by
// another request (409 response).
ErrResourceVersionConflict = apierror.ErrResourceVersionConflict

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i am thinking on this... i fell that we might be exposing an implementation detail (versions) of our entities on our api, which we shouldn't do imho.

instead we could say something more generic, like conflict because of concurrent update, without talking about "versions". wdty?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes, I agree

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants