{"record":{"id":"86813763ddfe7224","repo":"paperclipai/paperclip","slug":"cloud-runtime-identity-is-already-claimed-by-anoth","errorCode":null,"errorMessage":"Cloud runtime identity is already claimed by another assertion","messagePattern":"Cloud runtime identity is already claimed by another assertion","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"server/src/services/cloud-runtime-identity.ts","lineNumber":389,"sourceCode":"  if (!initialized) throw new Error(\"Cloud runtime identity provider is not initialized\");\n  const claims = verifyCloudRuntimeIdentityAssertion({\n    compactJws: input.compactJws,\n    env,\n    now: input.now,\n    // After a natural restart the provider env may already be canonical, but\n    // an identical retry of the original claim is still safe and idempotent.\n    // The durable row preserves the pool origin that assertion had to match\n    // on first application.\n    expectedPreviousOrigin: currentIdentity?.previousOrigin ?? startupOrigin,\n  });\n  const previousOrigin = claims.previousOrigin;\n  const canonicalOrigin = claims.canonicalOrigin;\n\n  const row = await input.db.transaction(async (tx) => {\n    const existing = await readPersistedIdentity(tx);\n    if (existing) {\n      if (!assertionsEqual(existing, claims)) {\n        throw new Error(\"Cloud runtime identity is already claimed by another assertion\");\n      }\n      return existing;\n    }\n\n    const now = input.now ?? new Date();\n    await tx\n      .insert(instanceSettings)\n      .values({\n        singletonKey: SINGLETON_KEY,\n        general: {\n          v: 1,\n          stackId: claims.sub,\n          claimId: claims.claimId,\n          previousOrigin,\n          canonicalOrigin,\n          stackSlug: claims.stackSlug,\n        },\n        experimental: {},","sourceCodeStart":371,"sourceCodeEnd":407,"githubUrl":"https://github.com/paperclipai/paperclip/blob/01ad8584922b5d85292b1723cae71fa0d9b07a19/server/src/services/cloud-runtime-identity.ts#L371-L407","documentation":"Inside the apply transaction, if a persisted runtime identity row already exists and its stored assertion does not equal the incoming claims (assertionsEqual compares the canonical serialized fields), the instance is considered owned by a different assertion. This throw prevents a second, different assertion from hijacking an already-claimed instance.","triggerScenarios":"applyCloudRuntimeIdentityAssertion called with a compactJws whose claims differ from the persisted identity row: re-claiming with a new claimId, new keypair, or changed origins after the instance was already claimed.","commonSituations":"Rebuilding/replacing the runtime without clearing the instance's persisted identity; key rotation minting a new assertion for an already-claimed instance; pointing two runtimes at the same instance DB; retrying with a regenerated assertion after a partial failure.","solutions":["Replay the ORIGINAL assertion exactly (it is idempotent and returns the existing row)","If a new identity is genuinely required, clear/release the persisted runtime identity through the intended re-claim/teardown flow, then apply the new assertion","Verify you are not pointing a second runtime at another runtime's database","Compare the persisted assertion with the incoming one to confirm which fields differ"],"exampleFix":"// before\nawait applyCloudRuntimeIdentityAssertion({ db, compactJws: newlyMintedJws }); // new keypair\n// after\nawait applyCloudRuntimeIdentityAssertion({ db, compactJws: originalJws }); // identical retry is idempotent","handlingStrategy":"try-catch","validationCode":"const existing = await readPersistedIdentity(db);\nif (existing) {\n  const incoming = decodeJwtPayload(jws);\n  if (incoming.sub !== existing.stackId || incoming.claimId !== existing.claimId) {\n    throw new Error('instance already claimed; replay original assertion or release first');\n  }\n}","typeGuard":null,"tryCatchPattern":"try {\n  await applyCloudRuntimeIdentityAssertion({ db, compactJws: jws });\n} catch (e) {\n  if (e.message.includes('already claimed by another assertion')) {\n    // Not retryable with this jws: fetch/release existing claim or use the original assertion\n    throw new ClaimConflictError(e);\n  }\n  throw e;\n}","preventionTips":["Persist and replay the original assertion verbatim; application is idempotent for identical retries","Use the official release/teardown flow before claiming with a new identity","Ensure one runtime owns one instance database","Alert on any attempt to claim an already-claimed instance — it usually means a provisioning bug"],"tags":["auth","conflict","database"],"backgroundTag":"invalid-state-transition","analyzedSha":"01ad8584922b5d85292b1723cae71fa0d9b07a19","analyzedAt":"2026-09-10T03:14:50.855Z","contentChangedAt":"2026-09-10T03:14:50.855Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}