{"record":{"id":"49d46635778cca62","repo":"hcengineering/platform","slug":"modification-is-not-allowed","errorCode":null,"errorMessage":"Modification is not allowed","messagePattern":"Modification is not allowed","errorType":"exception","errorClass":"PlatformError","httpStatus":null,"severity":"error","filePath":"foundations/core/packages/core/src/proxy.ts","lineNumber":55,"sourceCode":"    }\n    if (value instanceof Set) {\n      throw new PlatformError(unknownError('Set is not allowed in model'))\n    }\n    return new Proxy(value, _createFreezeProxy(value))\n  }\n  return value\n}\n/**\n * @internal\n */\nexport function _createFreezeProxy (doc: Doc): ProxyHandler<Doc> {\n  return {\n    get (target: any, property: string, receiver: any): any {\n      const value = target[property]\n      return freeze(value)\n    },\n    set (target, p, newValue, receiver): any {\n      throw new PlatformError(unknownError('Modification is not allowed'))\n    },\n    defineProperty (target, property, attributes): any {\n      throw new PlatformError(unknownError('Modification is not allowed'))\n    },\n\n    deleteProperty (target, p): any {\n      throw new PlatformError(unknownError('Modification is not allowed'))\n    },\n    setPrototypeOf (target, v): any {\n      throw new PlatformError(unknownError('Modification is not allowed'))\n    }\n  }\n}\n\n/**\n * @internal\n */\nexport function _toDoc<D extends Doc> (doc: D): D {","sourceCodeStart":37,"sourceCodeEnd":73,"githubUrl":"https://github.com/hcengineering/platform/blob/63e28dc96483967b2fc21c881b3f1023c1de7718/foundations/core/packages/core/src/proxy.ts#L37-L73","documentation":"Model documents are handed out as read-only freeze proxies; the proxy's set trap unconditionally throws this PlatformError on any property assignment. The model is immutable from the client's perspective — mutations must go through transactions/update APIs, never direct property writes. Note that errors thrown inside a Proxy set trap surface at the assignment site, which may be far from the model code.","triggerScenarios":"Writing doc.someField = value on any object obtained from the model/query results (e.g. inside helpers like groupByArray or while processing queried docs), or via Object.assign(doc, {...}) and destructuring-with-reassignment on a frozen doc.","commonSituations":"Mutating a fetched document in place before saving; augmenting query results with computed fields; cache-style code assuming plain mutable objects; copying patterns that rely on assignment into the same object.","solutions":["Use the library's update/transaction API ($set) to change document data instead of direct assignment.","Unwrap the proxy with _toDoc(doc) only if you need to read internals — but perform writes through the proper API.","Build a new plain object (spread) for derived/computed results instead of mutating the frozen doc.","Clone fields you need to modify: const copy = { ...toDoc(doc) }; copy.field = x; then persist copy via update."],"exampleFix":"// before\ndoc.title = 'new title'\nawait tx.updateDoc(doc)\n// after\nawait tx.updateDoc(_class, _id, _id, { $set: { title: 'new title' } })","handlingStrategy":"try-catch","validationCode":"function isFrozenModelDoc(v: unknown): boolean {\n  return v != null && typeof v === 'object' && (v as any).$___proxy_target !== undefined\n}\nif (!isFrozenModelDoc(doc)) {\n  // safe-ish plain object; still prefer the update API for persistence\n}","typeGuard":"function isMutableCopy<T extends object>(v: T): v is T & { __mutable: true } {\n  return Object.isFrozen(v) === false && (v as any).$___proxy_target === undefined\n}","tryCatchPattern":"try {\n  (doc as any).title = 'x'\n} catch (e) {\n  if (e instanceof PlatformError && e.message.includes('Modification is not allowed')) {\n    await tx.updateDoc(_class, _id, _id, { $set: { title: 'x' } })\n  } else throw e\n}","preventionTips":["Treat all query/model results as immutable; never assign to their properties.","Use the update API ($set) for every mutation.","Create plain-object copies ({ ...toDoc(doc) }) for computed or grouped results.","Avoid Object.assign on model docs — it triggers the same proxy traps."],"tags":["proxy","immutability","model"],"backgroundTag":"object-is-frozen","analyzedSha":"63e28dc96483967b2fc21c881b3f1023c1de7718","analyzedAt":"2026-08-29T15:21:27.377Z","schemaVersion":2},"datasetVersion":"2026-08-29T17:17:51.833Z"}