REST API document metadata update fails with 409 Conflict when multiple users edit

We’re using Windchill 12.0 CPS05 REST API to update document metadata from an external system. When multiple users or automated processes try to update the same document simultaneously, we get 409 Conflict errors. The API response indicates a version mismatch, but we’re not sure how to handle this properly. Our integration updates metadata fields like status, owner, and custom attributes based on external workflow triggers.

API response:


HTTP/1.1 409 Conflict
{"error":"Version mismatch","message":"Document modified by another user"}

This causes metadata sync failures and inconsistencies between our external system and Windchill. How should we implement proper conflict resolution for concurrent updates?

Here’s a complete solution covering all three aspects of handling concurrent updates:

Optimistic Concurrency Control: Windchill’s REST API uses ETags to implement optimistic locking. The proper update flow is:


// Pseudocode - ETag-based update flow:
1. GET /documents/{id} - Receive ETag in response header
2. Extract ETag value from response
3. Apply metadata changes to document object
4. PUT /documents/{id} with If-Match: {ETag} header
5. If 409 conflict: goto step 1 (with backoff delay)
6. If 200 success: update complete

Implement a maximum retry count (3-5 attempts) to prevent infinite loops. Use exponential backoff: 1s, 2s, 4s between retries.

ETag/Version Headers: Always include version headers in your API requests:

  • If-Match: Use for updates - ensures you’re modifying the expected version
  • If-None-Match: Use for conditional GETs - avoids fetching unchanged documents
  • If-Modified-Since: Useful for polling scenarios to reduce bandwidth

Example headers:


GET /documents/12345
Response: ETag: "v1.2.45"

PUT /documents/12345
If-Match: "v1.2.45"
Content-Type: application/json

The ETag format varies but typically includes version iteration. Never parse or construct ETags manually - treat them as opaque tokens.

Conflict Resolution Strategies: Implement intelligent conflict handling based on your business requirements:

  1. Last-Write-Wins: Simple retry with fresh data (acceptable for low-value metadata)
  2. Merge Strategy: Fetch latest, intelligently merge your changes, retry update
  3. User Notification: For critical conflicts, notify users and require manual resolution
  4. Field-Level Locking: Use PATCH for granular updates, reducing conflict surface

For your scenario with external workflow triggers, implement merge logic:


// Pseudocode - Conflict resolution with merge:
1. Attempt initial update with cached ETag
2. On 409 conflict:
   a. GET latest document state
   b. Compare your changes vs current state
   c. Apply merge rules:
      - Status changes: external system wins
      - Owner changes: preserve if changed by user
      - Custom attrs: merge if non-overlapping
   d. Retry update with new ETag
3. Log all conflicts for audit trail

For high-contention documents, implement a queuing mechanism in your external system. Serialize updates to the same document using a distributed lock (Redis, database advisory locks) or message queue. This prevents multiple processes from competing for the same document.

Monitor 409 error rates to identify hot-spot documents that need architectural changes - perhaps splitting metadata across multiple objects or implementing a different update pattern like event-based eventual consistency.

Implement comprehensive logging: record ETag values, retry attempts, merge decisions, and final outcomes. This audit trail is crucial for troubleshooting sync inconsistencies and understanding concurrent access patterns in your integration.

Thanks, that makes sense. So the workflow would be: GET document with ETag, apply my changes, PUT with If-Match header containing the ETag. If 409, repeat the process. But what about race conditions? If two processes both GET the document at the same time, apply different changes, and then both try to PUT, one will still fail, right?

Correct, that’s inherent to optimistic locking. The second PUT will fail with 409, forcing a retry. That’s actually the desired behavior - it prevents lost updates. For high-contention scenarios, implement exponential backoff in your retry logic to reduce collision probability. Also consider implementing a distributed lock or queue mechanism in your external system to serialize updates to the same document.

The 409 error is Windchill’s optimistic concurrency control in action. You need to use ETags to handle concurrent updates properly. When you GET a document, the response includes an ETag header with the current version identifier. Include this ETag in your PUT/PATCH request using the If-Match header. If someone else modified the document in the meantime, you’ll get 409, then you can retrieve the latest version and retry your update.

We implemented retry logic for this exact scenario. When you get a 409, fetch the latest document version with GET, merge your changes with the current state, and retry the update with the new ETag. Just be careful about overwriting changes from other users - you might need business logic to determine which updates take precedence.