hcengineering/platform · error · PlatformError
Map is not allowed in model
Error message
Map is not allowed in model
What it means
The library's model/Doc values are exposed as immutable freeze proxies, and freeze() recursively wraps values it returns. JavaScript Map instances cannot be wrapped by this proxy mechanism (per-field model values must be plain serializable data), so encountering a Map throws a PlatformError. It signals that a non-plain-data structure leaked into the model.
Source
Thrown at foundations/core/packages/core/src/proxy.ts:36
if (property === PROXY_MIXIN_CLASS_KEY) {
return mixin._id
}
const value = target[mixin._id]?.[property]
if (value === undefined) {
return ancestorProxy !== null ? ancestorProxy.get?.(target, property, receiver) : target[property]
}
return value
}
}
}
export function freeze (value: any): any {
if (value != null && typeof value === 'object') {
if (Array.isArray(value)) {
return value.map((it) => freeze(it))
}
if (value instanceof Map) {
throw new PlatformError(unknownError('Map is not allowed in model'))
}
if (value instanceof Set) {
throw new PlatformError(unknownError('Set is not allowed in model'))
}
return new Proxy(value, _createFreezeProxy(value))
}
return value
}
/**
* @internal
*/
export function _createFreezeProxy (doc: Doc): ProxyHandler<Doc> {
return {
get (target: any, property: string, receiver: any): any {
const value = target[property]
return freeze(value)
},
set (target, p, newValue, receiver): any {View on GitHub (pinned to 63e28dc964)
Solutions
- Replace the Map with a plain Record/object: Object.fromEntries(map) when writing the field.
- Keep Maps outside the Doc model (module-level caches, WeakMaps) and store only serializable data in docs.
- Convert at the boundary: when importing data, normalize Maps to plain objects before saving.
Example fix
// before
const doc = { palette: new Map([['white', '#fff']]) }
// after
const doc = { palette: Object.fromEntries([['white', '#fff']]) } Defensive patterns
Strategy: validation
Validate before calling
function assertModelSafe(value: unknown, depth = 0): void {
if (value == null || typeof value !== 'object' || depth > 8) return
if (value instanceof Map) throw new TypeError('Map is not allowed in model; use a plain object')
if (value instanceof Set) throw new TypeError('Set is not allowed in model; use an array')
if (Array.isArray(value)) { value.forEach((v) => assertModelSafe(v, depth + 1)); return }
for (const v of Object.values(value)) assertModelSafe(v, depth + 1)
}
assertModelSafe(docBeforeSave) Type guard
function isPlainObject(v: unknown): v is Record<string, unknown> {
if (v == null || typeof v !== 'object') return false
const proto = Object.getPrototypeOf(v)
return proto === Object.prototype || proto === null
} Try / catch
try {
const data = modelDoc.someField
use(data)
} catch (e) {
if (e instanceof PlatformError && e.message.includes('Map is not allowed in model')) {
console.error('A Map leaked into the model; convert with Object.fromEntries(map) before storing.')
} else throw e
} Prevention
- Only store JSON-serializable plain objects, arrays, and primitives in doc fields.
- Convert Maps with Object.fromEntries at the write boundary.
- Add a deep model-safety assertion in tests for domain classes attached to docs.
When it happens
Trigger: Storing or returning a Map as a document field value, e.g. { data: new Map([['a', 1]]) } in a Doc, then reading that doc through the frozen proxy (any get on a model object that returns the Map). Callers include attribute getters like whitePalette/avatarWhiteColors that read model objects.
Common situations: Using Map for convenience in domain classes attached to docs; deserializing data that came back as Map (some YAML/ORM libs); upgrading code where a field type changed from plain object to Map.
Related errors
- Set is not allowed in model
- Modification is not allowed
- ancestors not found: ${_class}
- class not found: ${_class}
- Method '${methodName}' not found in service implementation
AI-assisted analysis of hcengineering/platform@63e28dc964 (2026-08-29).
Data as JSON: /api/errors/9961991ba9cb26aa.
Report an issue: GitHub.