{"record":{"id":"4df230e9e01e5cd7","repo":"clockworklabs/SpacetimeDB","slug":"transaction-retry-failed-again","errorCode":null,"errorMessage":"transaction retry failed again","messagePattern":"transaction retry failed again","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"critical","filePath":"crates/bindings-typescript/src/server/runtime.ts","lineNumber":367,"sourceCode":"      sys.procedure_abort_mut_tx();\n      throw e;\n    }\n  };\n\n  let res = run();\n  try {\n    sys.procedure_commit_mut_tx();\n    return res;\n  } catch {\n    // ignore the commit error\n  }\n  console.warn('committing anonymous transaction failed');\n  res = run();\n  try {\n    sys.procedure_commit_mut_tx();\n    return res;\n  } catch (e) {\n    throw new Error('transaction retry failed again', { cause: e });\n  }\n}\n\ntype FlatSubmoduleDispatch = {\n  reducerFns: Reducers;\n  reducerDefs: RawReducerDefV10[];\n  procedureFns: Procedures;\n  procedureDefs: RawProcedureDefV10[];\n  anonViewFns: AnonViews;\n  viewFns: Views;\n  tables: Array<{ accessorName: string; tableDef: RawTableDefV10 }>;\n  schemaTables: Record<string, UntypedTableDef>;\n  typespace: Typespace;\n  dbView_: DbView<any> | undefined;\n  queryBuilder_: QueryBuilder<any> | undefined;\n  /** e.g. \"alias.\" for a submodule with namespace alias \"alias\" */\n  namePrefix: string;\n  subDispatches: SubmoduleDispatchInfo[];","sourceCodeStart":349,"sourceCodeEnd":385,"githubUrl":"https://github.com/clockworklabs/SpacetimeDB/blob/524b4487d949b61a07d4f39c862d1290259dfd20/crates/bindings-typescript/src/server/runtime.ts#L349-L385","documentation":"Procedures run inside anonymous transactions via runWithTx: the body executes, then sys.procedure_commit_mut_tx() commits. If the first commit throws, the runtime logs 'committing anonymous transaction failed', replays the whole transaction once, and commits again; a second commit failure throws 'transaction retry failed again' with the underlying host error attached as `cause`.","triggerScenarios":"Any host-side commit error occurring twice in a row: a datastore error at commit time, resource/budget exhaustion, or a deterministic failure caused by the procedure's own writes (a deterministically failing write fails identically on replay).","commonSituations":"Module under load hitting host limits; writes that violate host-level constraints surfacing only at commit; transient host storage issues where the single built-in retry is not enough.","solutions":["Inspect error.cause: it carries the real sys error that made both commits fail","If the cause is deterministic (constraint or budget violation), fix the procedure body; a blind retry cannot succeed","If the cause looks transient/host-level, check spacetimedb host logs and resource limits for the instance","If the data should legitimately commit, report an issue with the cause attached and the module hash"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"try {\n  await runProcedure();\n} catch (e) {\n  const cause = (e as Error)?.cause ?? e;\n  if (isTransientHostError(cause)) {\n    scheduleRetryWithBackoff(); // procedure must be idempotent\n  } else {\n    logAndAlert('procedure commit failed', { cause });\n  }\n}","preventionTips":["Always inspect and log error.cause; the outer message alone hides the real failure","Keep procedure writes within host constraints and budgets; deterministic failures cannot be retried away","Make procedures idempotent so an external retry after a failed commit is safe","Watch for the 'committing anonymous transaction failed' warning in logs as an early signal"],"tags":["transaction","database","procedure","typescript"],"backgroundTag":"transaction-commit-failed","analyzedSha":"524b4487d949b61a07d4f39c862d1290259dfd20","analyzedAt":"2026-08-16T23:58:54.611Z","schemaVersion":2},"datasetVersion":"2026-08-17T04:17:16.089Z"}