{"record":{"id":"e17d6f45b1a58940","repo":"pydantic/monty","slug":"what-must-be-a-canonical-uuid-string","errorCode":null,"errorMessage":"${what} must be a canonical uuid string","messagePattern":"(.+?) must be a canonical uuid string","errorType":"validation","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"crates/monty-js/ts/worker/value.ts","lineNumber":241,"sourceCode":"    if (!(1 in pair)) throw new TypeError('ClassType attr value missing')\n    attrPairs.push([pair[0], pair[1]])\n  }\n  return {\n    name: String(object.name),\n    id: uuidString(object.id, 'ClassType id'),\n    hostDefined: object.hostDefined === true,\n    isDataclass: object.isDataclass === true,\n    attrs: pushPairs(attrPairs, nodes),\n  }\n}\n\n/** A canonical uuid string is required for identities crossing the wire. */\nfunction uuidString(value: unknown, what: string): string {\n  if (\n    typeof value !== 'string' ||\n    !/^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$/.test(value)\n  ) {\n    throw new TypeError(`${what} must be a canonical uuid string`)\n  }\n  return value.toLowerCase()\n}\n\n/** Validates and converts a sandbox file-handle marker. */\nfunction pushFileHandle(object: Record<string, unknown>): ValueNode {\n  if (typeof object.path !== 'string') throw new TypeError('MontyFileHandle path must be a string')\n  if (typeof object.mode !== 'string') throw new TypeError('MontyFileHandle mode must be a string')\n  const position = object.position === undefined ? 0 : object.position\n  validateFilePosition(position)\n  return {\n    tag: 'file-handle',\n    val: { path: object.path, mode: canonicalFileMode(object.mode), position: BigInt(position) },\n  }\n}\n\n/** Appends key/value pairs while preserving their insertion order. */\nfunction pushPairs(pairs: [unknown, unknown][], nodes: ValueNode[]): NodePair[] {","sourceCodeStart":223,"sourceCodeEnd":259,"githubUrl":"https://github.com/pydantic/monty/blob/adc986b362e3961f407868cb118a99fe831b9e61/crates/monty-js/ts/worker/value.ts#L223-L259","documentation":"Identities (class instances, class types) crossing the wasm boundary must be canonically-formatted UUID strings (8-4-4-4-12 hex digits, hyphen-separated). uuidString validates the `id` field of such markers and throws this TypeError with the given label (`what`) when the value is missing, not a string, or not matching the UUID regex. It then lowercases the uuid for the wire.","triggerScenarios":"Passing a ClassInstance/ClassType marker with `id` set to a plain string like `'abc123'`, a number, a NaN-generated id, or an id with braces/urn prefix like `'{...}'` or `'urn:uuid:...'`. Also when `id` is undefined because it was never assigned.","commonSituations":"Using `Math.random()`-based ids instead of real UUIDs (e.g. crypto.randomUUID()); passing UUIDs in non-canonical formats (braces, no hyphens, uppercase-only frameworks); forgetting to persist and reuse a stable id across calls.","solutions":["Generate ids with `crypto.randomUUID()` which always produces the canonical hyphenated form.","Normalize existing ids: strip `urn:uuid:` prefix and braces, insert hyphens, e.g. via a regex rewrite before validation.","Check for undefined/null ids — the property may simply be missing on the marker object.","Validate before the call: `/^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$/.test(id)`."],"exampleFix":"// before\nconst marker = { [TYPE_MARKER]: 'ClassType', name: 'Foo', id: Math.random().toString(36) }\n// after\nconst marker = { [TYPE_MARKER]: 'ClassType', name: 'Foo', id: crypto.randomUUID() }","handlingStrategy":"validation","validationCode":"const UUID_RE = /^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$/;\nif (typeof marker.id !== 'string' || !UUID_RE.test(marker.id)) {\n  marker.id = crypto.randomUUID();\n}","typeGuard":"const isUuid = (v: unknown): v is string =>\n  typeof v === 'string' &&\n  /^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$/.test(v);","tryCatchPattern":"try {\n  await session.feedRun(code, { inputs: { inst: marker } });\n} catch (e) {\n  if (e instanceof TypeError && e.message.endsWith('must be a canonical uuid string')) {\n    marker.id = normalizeToUuid(marker.id); // strip urn:/braces, insert hyphens, or regenerate\n  } else throw e;\n}","preventionTips":["Always generate identities with crypto.randomUUID()","Strip urn:uuid: prefixes and braces when accepting ids from external systems","Reuse one stable uuid per logical class/instance across calls instead of regenerating","Add an isUuid assertion at the boundary where markers are created"],"tags":["typescript","wasm","uuid","identity","value-conversion"],"backgroundTag":"invalid-argument-format","analyzedSha":"adc986b362e3961f407868cb118a99fe831b9e61","analyzedAt":"2026-09-13T19:19:18.698Z","contentChangedAt":"2026-09-13T19:19:18.698Z","schemaVersion":2},"datasetVersion":"2026-09-14T11:17:12.474Z"}