{"record":{"id":"d7dd99eebc41cd07","repo":"nexu-io/open-design","slug":"invalid-live-artifact-refresh-id","errorCode":null,"errorMessage":"invalid live artifact refresh id","messagePattern":"invalid live artifact refresh id","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"apps/daemon/src/live-artifacts/store.ts","lineNumber":450,"sourceCode":"  };\n  if (finishedAt !== undefined) entry.finishedAt = finishedAt;\n  if (durationMs !== undefined) entry.durationMs = durationMs;\n  if (options.source !== undefined) entry.source = options.source;\n  if (options.error !== undefined) entry.error = compactLiveArtifactRefreshError(options.error);\n  if (options.metadata !== undefined) entry.metadata = options.metadata;\n  return entry;\n}\n\nfunction formatRefreshId(refreshOrdinal: number): string {\n  if (!Number.isSafeInteger(refreshOrdinal) || refreshOrdinal < 1) {\n    throw new Error('invalid live artifact refresh ordinal');\n  }\n  return `refresh-${refreshOrdinal.toString().padStart(6, '0')}`;\n}\n\nfunction parseRefreshOrdinal(refreshId: string): number {\n  const match = /^refresh-(\\d+)$/.exec(refreshId);\n  if (match === null) throw new Error('invalid live artifact refresh id');\n  const refreshOrdinal = Number(match[1]);\n  if (!Number.isSafeInteger(refreshOrdinal) || refreshOrdinal < 1) {\n    throw new Error('invalid live artifact refresh id');\n  }\n  return refreshOrdinal;\n}\n\nfunction defaultRefreshState(projectId: string, artifactId: string): LiveArtifactRefreshState {\n  return { schemaVersion: 1, projectId, artifactId, nextRefreshOrdinal: 1 };\n}\n\nfunction normalizeRefreshState(value: unknown, projectId: string, artifactId: string): LiveArtifactRefreshState {\n  if (!value || typeof value !== 'object' || Array.isArray(value)) {\n    throw validationError('refresh-state.json', 'live artifact refresh state must be an object');\n  }\n  const raw = value as Record<string, unknown>;\n  if (raw.schemaVersion !== 1) throw validationError('refresh-state.json.schemaVersion', 'live artifact refresh state schemaVersion must be 1');\n  if (raw.projectId !== projectId) throw validationError('refresh-state.json.projectId', 'live artifact refresh state projectId does not match requested project');","sourceCodeStart":432,"sourceCodeEnd":468,"githubUrl":"https://github.com/nexu-io/open-design/blob/5be4028344c2eb4c667c5a97bda8f750c5597ef7/apps/daemon/src/live-artifacts/store.ts#L432-L468","documentation":"Thrown by parseRefreshOrdinal() when a refreshId does not match the canonical shape `/^refresh-(\\d+)$/`. Refresh ids are minted only by formatRefreshId() as `refresh-NNNNNN` (zero-padded to 6 digits), so any other shape means the caller fabricated or corrupted the id. This is the regex-fail branch (line 450); the numeric-range branch is a separate throw at line 453.","triggerScenarios":"Passing `refresh-1` without padding is actually accepted by the regex (\\d+ matches), but passing `refresh_000001`, `refresh-000001a`, `r-000001`, `000001`, or an empty string fails the regex and throws here. Also triggered by passing a briefDraftId or lockId where a refreshId is expected.","commonSituations":"Caller stores the wrong field from the lock acquisition result; client increments its own counter and formats it inconsistently; log/state file was hand-edited;混淆 between briefDraftId, lockId, and refreshId.","solutions":["Always pass the refreshId exactly as returned by acquireLiveArtifactRefreshLock() (metadata.refreshId).","If you persisted the id externally, store the full `refresh-NNNNNN` string, not just the ordinal number.","Do not construct refresh ids client-side; acquire a lock to obtain a fresh one.","If state files are corrupted, delete refresh-state.json and refresh.lock.json and re-acquire."],"exampleFix":"// before\nmarkLiveArtifactRefreshCommitted({ ..., refreshId: '1' });\n// after\nconst lock = await acquireLiveArtifactRefreshLock({ ... });\nmarkLiveArtifactRefreshCommitted({ ..., refreshId: lock.metadata.refreshId }); // 'refresh-000001'","handlingStrategy":"validation","validationCode":"const REFRESH_ID = /^refresh-(\\d+)$/;\n\nfunction isRefreshIdShape(value: unknown): value is string {\n  return typeof value === 'string' && REFRESH_ID.test(value);\n}\n\nif (!isRefreshIdShape(refreshId)) {\n  throw new Error(`refreshId must look like 'refresh-NNNNNN'; got ${JSON.stringify(refreshId)}`);\n}","typeGuard":"function isRefreshId(value: unknown): value is `refresh-${string}` {\n  return typeof value === 'string' && /^refresh-\\d+$/.test(value);\n}","tryCatchPattern":null,"preventionTips":["Always source refreshId from acquireLiveArtifactRefreshLock().metadata.refreshId.","Persist the full `refresh-NNNNNN` string externally, never the bare number.","Do not hand-construct refresh ids."],"tags":["live-artifacts","refresh","validation","id-format"],"backgroundTag":null,"analyzedSha":"5be4028344c2eb4c667c5a97bda8f750c5597ef7","analyzedAt":"2026-08-12T12:03:58.812Z","schemaVersion":2},"datasetVersion":"2026-08-12T18:17:37.767Z"}