Repository navigation
fix(s3): 🐛 accept a refused write when the object is the call's own - #370
Merged
Merged
Conversation
The SDK retries a PutObject whose response the network lost, and the retry meets the object the first attempt stored. The backend refuses the conditional write, and the adapter returned ErrPathExists for a Put that had succeeded, so the commit on top of it failed. A Quarry run against R2 met this after a long stall and lost ninety minutes of work. The adapter now answers a refusal by reading the object's length and ETag, which an S3 store gives a single-part object as the MD5 of its bytes. When both equal the payload's, Put returns success. A multipart ETag never matches, and a refusal the HEAD cannot confirm stays ErrPathExists. The storage contract states the rule, and the mock gives the ETag S3 gives. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Codex Review Summary: ✅ CompletedThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
Bosun's changelog rule C6 holds an entry to ninety words, and the entry ran to a hundred and three. The shorter entry says the same. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
A Quarry run against R2 stalled for ninety minutes on one write and then failed with
path already exists. The SDK had retried aPutObjectwhose response the network lost, and the retry met the object the first attempt had stored. The S3 adapter read the refusal as another writer's object, so aPutthat had succeeded returnedErrPathExists, and the commit on top of it failed. The adapter now recognises its own upload.Highlights
CONTRACT_STORAGE.md§Put: where the backend reports a content digest the adapter can compare with its payload's, a refused conditional create is a success when the stored object's length and digest equal the payload's. When either differs, or the comparison fails,PutreturnsErrPathExistsas before.Puthashes the payload as it spools it. On a precondition failure the atomic path reads the object'sHEADand returns nil when its length and ETag equal the payload's length and MD5, which an S3 store gives a single-part object. A multipart ETag carries a part count and never matches. AHEADthat fails leaves the refusal in place.HeadObjectreports length and ETag as S3 does.Putsucceed with the bytes in place. Another writer's object, aHEADthat fails, and a multipart ETag each keepErrPathExists. The existing duplicate-write test writes other bytes for the refusal and the same bytes for the success.Test Plan
task lintandtask testpass, with the four new cases and the adjusted duplicate-write case.fd46186a: no findings.d142e63dshortens it to 81.🤖 Generated with Claude Code