tts_source_revision_mismatch 409: stale expected_script_revision_id
Sume returns 409 tts_source_revision_mismatch when the accepted script changed under you or a run is frozen. How to re-read the revision and retry.

tts_source_revision_mismatch is a 409 from the Sume script-source API. It is the optimistic-concurrency error: the accepted script revision is not the one your request assumed. It has four triggers in the code, and the fix is always to read the current revision and decide again. All of these come back in Sume's standard error envelope with an HTTP status and a stable code, so branch on the code, not the message text.
The accept call, POST /v1/tts-1.0/source, takes script_texts and an optional expected_script_revision_id. If you pass it and the thread's current accepted revision is a different one, the answer is 409 with the message "Accepted revision changed." Pass null to say "I expect there is no accepted revision yet."
The four triggers
| Situation | Message | What to do |
|---|---|---|
| expected_script_revision_id differs from the thread's current revision | Accepted revision changed. | GET /v1/tts-1.0/source, merge, resubmit with the new id. |
| Generating with a revision not bound to this generation | The revision is not bound to this generation. | Use the revision accepted on this thread. |
| Run has no accepted source binding | This run has no accepted source binding. | Accept a script on the thread before the run starts. |
| Editing a frozen run | Accept edits on the thread, not an already frozen run. | Accept the edit on the thread, then start a new run. |
Safe update loop
The pattern is read, change, accept with the id you read, and on 409 start over. It stops two writers from silently replacing each other's script. Accepted revisions are immutable, so the previous revision and the jobs generated from it are untouched.
curl -s "https://api.sume.com/v1/tts-1.0/source" \
-H "x-api-key: $SUME_API_KEY" -H "content-type: application/json" \
-d "{\"script_texts\": [\"Hello there. Second sentence.\"], \"thread_id\": \"$THREAD\", \"expected_script_revision_id\": \"$REV\"}"Cost
A 409 is raised before dispatch, so it creates no job and no charge. The jobs you already generated from the older revision keep their receipts; verify-spine can re-adopt unchanged sentences when you pass explicit sentence_ids.
Sources
Related posts
More in Developers
- tts_source_too_large 422: Sume TTS 20,000-character cap on a selection
A transcript_source selection that resolves past 20,000 characters returns 422 tts_source_too_large. Split it by sentence ids and price each job.
- tts_text_source_conflict 400: transcript or transcript_source
Sume TTS wants exactly one of transcript and transcript_source. Sending both, neither or a malformed source returns 400. Which code, and how to fix.
- Sume TypeScript SDK createImage: a retired model id fails tsc
Sume's @sume-com/sdk lists accepted image model ids as a string union, so gpt-image-1 fails to compile. Use tsc as the migration checklist.
- TypeScript types for a Sume job status: narrow on sume_status
Type the Sume job envelope as a discriminated union on sume_status, so a switch covers queued to canceled and the compiler flags a missed case. Runs on Node 22.
Written by Sume