No documented Microsoft Graph v1.0 operation provides the complete OneDrive Personal guarantee requested: atomically compare the original file’s eTag at content publication, reject every intervening change, and replace that same driveItem ID.
Direct replacement
For:
PUT /drives/{drive-id}/items/{item-id}/content
Authorization: Bearer {token}
Content-Type: application/octet-stream
If-Match: E1
<file bytes>
the documented request headers are only Authorization and Content-Type; If-Match is not part of this operation’s documented contract. Therefore, even if a service implementation happens to accept it, applications cannot rely on a stale eTag producing 412 Precondition Failed. The documented behavior is simply to replace the content of the item identified by ID and return the resulting driveItem. ^1^
This means direct replacement does not have a documented optimistic-concurrency contract matching the requirement.
Upload sessions
The closest documented operation is creation of an update session by item ID:
POST /drives/{drive-id}/items/{item-id}/createUploadSession
Authorization: Bearer {token}
Content-Type: application/json
If-Match: E1
{
"deferCommit": true
}
On this request, If-Match is documented: if the supplied eTag or cTag does not match the item’s current tag, session creation returns 412 Precondition Failed. However, that comparison occurs when the upload session is created, not when its staged content is eventually published. The documentation does not state that E1 is retained and evaluated again at final commit. ^2^
For deferCommit: true, completion differs by storage provider:
- OneDrive for Business and SharePoint: zero-length
POST to the upload URL.
- OneDrive Personal: a final
PUT, using the documented upload-error recovery/commit form.
The OneDrive Personal recovery form is path-oriented and supplies a new driveItem description plus @microsoft.graph.sourceUrl:
PUT /v1.0/drives/{drive-id}/root:/{path-to-parent}
Authorization: Bearer {token}
Content-Type: application/json
If-Match: {etag-or-ctag}
{
"name": "filename.ext",
"@microsoft.graph.conflictBehavior": "replace",
"@microsoft.graph.sourceUrl": "{upload-session-URL}"
}
Although the documentation says If-Match can be used on this call, it does not state that this header conditions the original target item identified when the session was created, nor that path replacement preserves that item’s ID. It consequently does not establish the required same-item, commit-time comparison. The documented rename, replace, and fail values are filename-conflict behavior, not an equivalent target-item eTag contract. ^2^
Concurrent changes
Microsoft Graph defines:
-
eTag as the tag for the entire item—metadata and content.
-
cTag as the content tag, unchanged by metadata-only changes.
-
id as the item’s unique identifier within the drive. ^3^
Accordingly, an eTag is the appropriate token when rename or move changes must also invalidate an operation. But neither upload contract documents a final comparison of the original item’s eTag covering intervening content edits, renames, moves, deletion, or deletion/recreation.
The only applicable documented 412 guarantee is at createUploadSession time. A later filename conflict can instead produce 409 Conflict when the final range is uploaded. There is no documented guarantee that every stale-original-target case produces 412 at publication. ^2^
Lost final response and recovery
After a timeout:
- Query the upload URL with
GET.
A successful status response reports nextExpectedRanges and expirationDateTime, showing that the session remains resumable. It does not constitute a documented “not committed” verdict in every ambiguous-final-response case.
- Read the original item by ID:
GET /drives/{drive-id}/items/{item-id}?$select=id,eTag,cTag,size,name
Authorization: Bearer {token}
OneDrive Personal also supports includeDeletedItems=true when retrieving an item by ID. This can determine whether the original ID still exists or is deleted and expose its current tags, but tags alone do not prove that a particular attempted payload was published. ^4^
- If the session is still active and publication must be prevented, cancel it:
DELETE {uploadUrl}
204 No Content documents successful cleanup of the temporary upload. Otherwise, stop sending fragments or commit requests and wait for the reported expiration; the session must be committed before that time. Temporary cleanup may occur later. ^2^
The documentation recommends resuming or retrying interrupted and 5xx uploads, using exponential backoff for 5xx, and restarting when upload-session status returns 404. It does not document an idempotency key, exactly-once commit, or a read-only status that unambiguously classifies all three states—committed, rejected, and pending—after a lost final response.
If this concurrency property is mandatory, it must be enforced outside this API contract, such as by serializing writes through an application-controlled coordinator. A pre-commit read followed by upload is not equivalent because another write can occur between those operations.
References
- Upload or replace the contents of a driveItem
- driveItem: createUploadSession
- driveItem resource type
- Get driveItem