{"record":{"id":"d4c3967cfaa4f695","repo":"paperclipai/paperclip","slug":"persisted-cloud-runtime-identity-contains-an-inval-d4c396","errorCode":null,"errorMessage":"Persisted Cloud runtime identity contains an invalid stack slug","messagePattern":"Persisted Cloud runtime identity contains an invalid stack slug","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"server/src/services/cloud-runtime-identity.ts","lineNumber":166,"sourceCode":"      return [];\n    }\n  })();\n  env.PAPERCLIP_RUNTIME_API_CANDIDATES_JSON = JSON.stringify([\n    identity.canonicalOrigin,\n    ...existingCandidates.filter((candidate) => candidate !== identity.canonicalOrigin),\n  ]);\n}\n\nfunction assertPersistedIdentityMatchesStack(row: PersistedRuntimeIdentity, env: NodeJS.ProcessEnv) {\n  const configuredStackId = nonEmpty(env.PAPERCLIP_CLOUD_STACK_ID);\n  if (!configuredStackId || configuredStackId !== row.stackId) {\n    throw new Error(\"Persisted Cloud runtime identity does not match PAPERCLIP_CLOUD_STACK_ID\");\n  }\n  if (!exactHttpsOrigin(row.previousOrigin) || !exactHttpsOrigin(row.canonicalOrigin)) {\n    throw new Error(\"Persisted Cloud runtime identity contains an invalid origin\");\n  }\n  if (!STACK_SLUG_PATTERN.test(row.stackSlug) || new URL(row.canonicalOrigin).hostname.split(\".\")[0] !== row.stackSlug) {\n    throw new Error(\"Persisted Cloud runtime identity contains an invalid stack slug\");\n  }\n}\n\n/** Load the durable claim before auth, routes, and child-runtime configuration. */\nexport async function initializeCloudRuntimeIdentity(\n  db: Db,\n  env: NodeJS.ProcessEnv = process.env,\n): Promise<CloudRuntimeIdentitySnapshot | null> {\n  startupOrigin = configuredStartupOrigin(env);\n  // Self-hosted servers have no Cloud stack identity to restore. Avoid touching\n  // the singleton table on that path; besides keeping the feature inert, this\n  // preserves lightweight startup/test database seams that intentionally do\n  // not construct a database client.\n  if (!nonEmpty(env.PAPERCLIP_CLOUD_STACK_ID)) {\n    initialized = true;\n    currentIdentity = null;\n    return null;\n  }","sourceCodeStart":148,"sourceCodeEnd":184,"githubUrl":"https://github.com/paperclipai/paperclip/blob/01ad8584922b5d85292b1723cae71fa0d9b07a19/server/src/services/cloud-runtime-identity.ts#L148-L184","documentation":"The persisted Cloud runtime identity must satisfy two slug invariants: stackSlug matches STACK_SLUG_PATTERN (lowercase alphanumeric/hyphens, 2-63 chars, starts and ends alphanumeric), and the first label of canonicalOrigin's hostname equals the stackSlug. This binds the durable claim's slug to the actual DNS name the instance is served from. If either check fails at startup, this error is thrown.","triggerScenarios":"initializeCloudRuntimeIdentity loads a persisted identity where row.stackSlug fails STACK_SLUG_PATTERN (uppercase, underscores, leading/trailing hyphen, too long, or empty), or new URL(row.canonicalOrigin).hostname.split('.')[0] !== row.stackSlug (e.g. slug 'my-stack' but origin 'https://other.example.com').","commonSituations":"A Cloud deployment renamed the stack or its DNS hostname without re-claiming identity, so the persisted slug and origin no longer agree; a hand-edited or incorrectly migrated instance_settings row; a database restored from a different stack whose hostname prefix differs; a slug containing invalid characters was written by custom tooling.","solutions":["Make canonicalOrigin's hostname first label equal stackSlug — either fix the persisted canonicalOrigin to the correct '<slug>.<domain>' URL or correct the stackSlug in the instance_settings row (singletonKey 'cloud-runtime-identity/v1').","If the deployment's hostname legitimately changed (stack renamed), the clean path is a fresh instance claim for the new hostname rather than editing the old row, since the claim is one-time.","Check the slug against the pattern ^[a-z0-9]([a-z0-9-]{0,61}[a-z0-9])?$ before writing it via any custom migration."],"exampleFix":"// persisted row\n// before (slug/hostname mismatch)\nstackSlug: \"my-stack\", canonicalOrigin: \"https://wrong-name.example.com\"\n// after\nstackSlug: \"my-stack\", canonicalOrigin: \"https://my-stack.example.com\"","handlingStrategy":"validation","validationCode":"const STACK_SLUG_PATTERN = /^[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?$/;\nfunction slugMatchesOrigin(slug: string, canonicalOrigin: string): boolean {\n  try {\n    return STACK_SLUG_PATTERN.test(slug) &&\n      new URL(canonicalOrigin).hostname.split(\".\")[0] === slug;\n  } catch { return false; }\n}\n// before writing or deploying:\nif (!slugMatchesOrigin(stackSlug, canonicalOrigin)) throw new Error(\"stackSlug must be the first DNS label of canonicalOrigin\");","typeGuard":"function isValidIdentityPair(row: { stackSlug: string; canonicalOrigin: string }): boolean {\n  try {\n    return /^[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?$/.test(row.stackSlug) &&\n      new URL(row.canonicalOrigin).hostname.split(\".\")[0] === row.stackSlug;\n  } catch { return false; }\n}","tryCatchPattern":null,"preventionTips":["Always provision the hostname as '<stackSlug>.<domain>' so slug and DNS label agree","When renaming a stack or its hostname, re-run the identity claim instead of editing the persisted row","Validate slugs against the pattern before persisting them in custom tooling","Include the slug/origin pair in deploy-time smoke checks"],"tags":["cloud","identity","dns","validation","startup"],"backgroundTag":"invalid-identifier-format","analyzedSha":"01ad8584922b5d85292b1723cae71fa0d9b07a19","analyzedAt":"2026-09-10T03:14:50.855Z","contentChangedAt":"2026-09-10T03:14:50.855Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}