REST API document metadata update fails with 409 Conflict when using ETag

Our document management integration updates metadata for technical documents via REST API. We’re implementing ETag-based optimistic concurrency control but consistently getting 409 Conflict responses even when no other users are modifying the documents.

Request pattern:


GET /Windchill/servlet/odata/DocMgmt/Documents('12345')
ETag: "v2.1708523400000"

PATCH /Windchill/servlet/odata/DocMgmt/Documents('12345')
If-Match: "v2.1708523400000"
{"description": "Updated text"}

Response: 409 Conflict with message “The resource has been modified by another process”. We’re fetching the ETag immediately before the update, so version conflicts shouldn’t occur. Is there something specific about how Windchill handles version headers for document metadata updates?

For document updates specifically, consider using the X-PTC-IgnoreVersionCheck header if your use case allows it. This bypasses ETag validation and applies updates based on current state. Obviously only use this when you control all update sources and can guarantee no conflicting changes. For true concurrent editing scenarios, stick with ETag validation but implement proper conflict resolution.

Here’s the complete solution addressing optimistic concurrency control, ETag handling, and conflict resolution:

Optimistic Concurrency Control: Windchill’s ETag includes version iteration, timestamp, and internal state hash. Background processes (indexing, cache sync, lifecycle evaluators) can modify the state hash without version changes. Implement retry logic with exponential backoff:


// Pseudocode - Robust update with retry:
1. Set max_retries = 3, retry_delay = 500ms
2. For attempt in 1 to max_retries:
   - GET document and extract fresh ETag
   - Immediately PATCH with If-Match header
   - If 200 OK: break and return success
   - If 409 Conflict: wait retry_delay, double delay
   - If 412 Precondition Failed: version changed, abort
3. If all retries fail: log conflict and queue for manual review

ETag/Version Headers: Always fetch ETag immediately before update and include both If-Match and X-PTC-UpdateMode headers:


PATCH /DocMgmt/Documents('12345')
If-Match: "v2.1708523400000"
X-PTC-UpdateMode: optimistic
Content-Type: application/json

The X-PTC-UpdateMode header tells Windchill to use strict ETag validation rather than fallback to last-write-wins behavior.

Conflict Resolution Strategies:

  1. Retry with Fresh ETag (80% of conflicts resolve this way):

    • Fetch current state
    • Reapply your changes
    • Submit with new ETag
  2. Merge Strategy (for partial updates):

    • GET current document state
    • Merge your changes with current values
    • PATCH merged result
  3. Version-Based Resolution (for critical conflicts):

    • Check if version iteration changed (v2 → v3)
    • If yes: true concurrent edit, require manual review
    • If no: internal state change, safe to retry
  4. Pessimistic Lock Fallback (for sequential updates):

    • POST to /Documents(‘12345’)/Actions/CheckOut
    • Perform updates on working copy
    • POST to /Actions/CheckIn with updated content
    • This prevents concurrent modifications entirely

For your automation scenario, I recommend implementing retry logic first. If conflicts persist, consider whether your updates need strict concurrency control. For metadata-only changes that don’t affect version content, using X-PTC-IgnoreVersionCheck with a custom header like X-Client-UpdateToken can provide simpler conflict detection at the application level.

Monitor conflict rates over time. If you see >10% of updates hitting 409, investigate whether scheduled jobs or integrations are causing unnecessary document touches. Sometimes disabling real-time indexing for bulk update windows reduces conflicts significantly.

Also check if you have automatic workflow promotions or scheduled jobs running. We had a similar issue where a nightly job was updating document lifecycle states, causing ETags to change. The solution was to add retry logic with fresh ETag fetch on 409 responses. Usually succeeds on second attempt after the background process completes.

Windchill’s ETag format includes both version iteration and modification timestamp. If background processes like indexing or lifecycle state evaluation touch the document between your GET and PATCH, the ETag changes even though the visible version number stays the same. Try logging the full ETag value from both GET response and 409 error response to see what’s changing.

Good insights. I added logging and confirmed the ETag timestamp portion changes between GET and PATCH, even within a 2-second window. No scheduled jobs are running during our test window, and documents are in Released state with no active workflows. The modification appears to be internal to Windchill. Could search indexing or cache updates be triggering these micro-updates?