{"record":{"id":"bb3fc7a4e3a32d23","repo":"thedotmack/claude-mem","slug":"device-id-must-be-1-128-characters","errorCode":null,"errorMessage":"device_id must be 1-128 characters","messagePattern":"device_id must be 1-128 characters","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"workers/sync-hub/src/do/SyncHub.ts","lineNumber":623,"sourceCode":"\t\t\t\tconnection_state: connected.has(row.device_id) ? \"connected\" as const : \"disconnected\" as const,\n\t\t\t};\n\t\t});\n\t\treturn {\n\t\t\tprotocol_version: 1,\n\t\t\tuser_id: userId,\n\t\t\tepoch: this.meta(\"epoch\"),\n\t\t\thead_seq: head,\n\t\t\tprojected_seq: projected,\n\t\t\tprojection_lag_ops: decimalLag(head, projected),\n\t\t\tsync_health: head === projected ? \"healthy\" : \"projector_lagging\",\n\t\t\tdevices,\n\t\t};\n\t}\n\n\trenameDevice(deviceId: string, name: string): boolean {\n\t\tconst normalizedId = deviceId.trim();\n\t\tconst normalizedName = normalizeDeviceName(name);\n\t\tif (normalizedId.length === 0 || normalizedId.length > 128) throw invalid(\"device_id must be 1-128 characters\");\n\t\tif (normalizedName === null) throw invalid(\"name must be 1-80 characters\");\n\t\treturn this.ctx.storage.sql.exec(\n\t\t\t\"UPDATE devices SET name = ? WHERE device_id = ?\",\n\t\t\tnormalizedName,\n\t\t\tnormalizedId,\n\t\t).rowsWritten > 0;\n\t}\n\n\t// ---------------------------------------------------------------------\n\t// Authoritative projection checkpoint and short per-user lease.\n\t// ---------------------------------------------------------------------\n\n\tacquireProjectionLease(targetSeq: string, now = Date.now()): ProjectionLease {\n\t\tconst target = assertCanonicalDecimal(targetSeq);\n\t\tconst head = this.headSeq();\n\t\tif (compareCanonicalDecimals(target, head) > 0) throw projectionError(\"target_seq exceeds head_seq\");\n\t\tconst projected = this.projectedSeq();\n\t\tconst existingToken = this.metaOptional(\"projection_lease_token\");","sourceCodeStart":605,"sourceCodeEnd":641,"githubUrl":"https://github.com/thedotmack/claude-mem/blob/d8bc9755e74915e5c3b999181e10a67c889bce2a/workers/sync-hub/src/do/SyncHub.ts#L605-L641","documentation":"Validation guard in SyncHubDO.renameDevice: the trimmed deviceId must be 1-128 characters to match the device-id constraints enforced at registration. renameDevice updates the display name in the devices table and returns whether a row matched.","triggerScenarios":"Renaming with an empty id after trimming, or an id longer than 128 chars (e.g. a full URL or concatenated token passed as the id).","commonSituations":"Client storing a prefixed/over-long identifier, UI sending an untrimmed whitespace-only id, schema change where device ids became longer after migration.","solutions":["Trim the id and check length is between 1 and 128 before calling renameDevice","Reuse the exact device id issued at registration rather than a derived value","Check the return value: false means no device with that id exists, not a rename failure"],"exampleFix":"// before\nawait stub.renameDevice(rawId, name);\n// after\nconst id = rawId.trim();\nif (id.length === 0 || id.length > 128) throw new Error('invalid device id');\nawait stub.renameDevice(id, name);","handlingStrategy":"validation","validationCode":"const id = rawId.trim();\nif (id.length < 1 || id.length > 128) throw new Error('device id must be 1-128 chars');\nconst nm = normalizeDeviceName(name);\nif (nm === null) throw new Error('device name must be 1-80 chars');","typeGuard":"const isRenamableDeviceId = (id: unknown): id is string => typeof id === 'string' && id.trim().length >= 1 && id.trim().length <= 128;","tryCatchPattern":"try {\n  return await stub.renameDevice(deviceId, name);\n} catch (e) {\n  if (String(e).includes('device_id must be 1-128 characters')) return false;\n  throw e;\n}","preventionTips":["Store the canonical registered device id and reuse it verbatim","Trim ids and names in the UI before submitting","Enforce the 1-128 char constraint wherever device ids are created"],"tags":["validation","sync","devices"],"backgroundTag":"invalid-argument-value","analyzedSha":"d8bc9755e74915e5c3b999181e10a67c889bce2a","analyzedAt":"2026-09-17T16:40:26.182Z","contentChangedAt":"2026-09-17T16:40:26.182Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}