hcengineering/platform · error
Attribute not found: ${key}, ${cardPath}
Error message
Attribute not found: ${key}, ${cardPath} What it means
A defensive check inside createCardWithRelations: after masterTagAttributes.has(key) returns true, the map get() should never be undefined. Throwing here signals a race/modification between the has-check and the get, or a custom map implementation with inconsistent behavior.
Source
Thrown at packages/importer/src/huly/cards.ts:561
throw new Error('Blob file not found: ' + blobPath + ' from:' + cardPath)
}
blobProps[blobFile._id] = {
file: blobFile._id,
type: blobFile.type,
name: blobFile.name,
size: blobFile.size,
metadata: {} // todo: blobFile.metadata
}
}
cardProps.blobs = blobProps
}
const relations: UnifiedDoc<Doc>[] = []
for (const [key, value] of Object.entries(customProperties)) {
if (masterTagAttributes.has(key)) {
const attr = masterTagAttributes.get(key)
if (attr === undefined) {
throw new Error(`Attribute not found: ${key}, ${cardPath}`)
}
const attrProps = attr.props
const attrType = attrProps.type
const attrBaseType = attrType._class === core.class.ArrOf ? attrType.of : attrType
const values = attrType._class === core.class.ArrOf ? value : [value]
const propValues = []
for (const val of values) {
if (attrBaseType._class === core.class.RefTo) {
const refPath = path.resolve(path.dirname(cardPath), val)
const ref = this.metadataRegistry.getRef(refPath) as Ref<Card>
propValues.push(ref)
} else {
propValues.push(val)
}
}
cardProps[attrProps.name] = attrType._class === core.class.ArrOf ? propValues : propValues[0]View on GitHub (pinned to 63e28dc964)
Solutions
- Audit for concurrent mutation of masterTagAttributes during processing and snapshot the map before iterating cards.
- Ensure a genuine Map is passed (not a Map-like wrapper with divergent has/get).
- Log the key and map contents at failure to identify what removed the entry.
Example fix
// before await Promise.all(cards.map(c => this.processCard(c, masterTagAttributes))) // after — snapshot to avoid concurrent mutation const attrsSnapshot = new Map(masterTagAttributes) await Promise.all(cards.map(c => this.processCard(c, attrsSnapshot)))
Defensive patterns
Strategy: try-catch
Validate before calling
import fs from 'fs'
function hasMasterTagAttr(attrs: Map<string, unknown>, key: string): boolean {
return attrs instanceof Map && attrs.has(key)
} Type guard
function isRealMap<K, V>(m: unknown): m is Map<K, V> {
return m instanceof Map
} Try / catch
try {
await processor.cardWithRelations(cardPath)
} catch (e) {
if (e instanceof Error && e.message.startsWith('Attribute not found:')) {
console.error('masterTagAttributes was mutated or replaced mid-import — snapshot maps before processing')
} else throw e
} Prevention
- Don't mutate processor maps while an import is running; pass immutable snapshots.
- Ensure attributes are fully built before processing cards that reference them.
- Pass genuine Map instances, not proxies or Map-like wrappers.
When it happens
Trigger: Effectively unreachable in normal use — the key was just confirmed present in masterTagAttributes. It could only fire if masterTagAttributes is mutated concurrently, is a Map-like object whose has/get disagree, or a custom subclass overrides one of the methods inconsistently.
Common situations: Custom concurrency where another async task clears/rebuilds the attributes map mid-processing; wrapping the map in a proxy or passing a plain object masquerading as a Map.
Related errors
- Association not found: ${key}, ${cardPath}
- Unsupported card type: ${cardType} in ${cardPath}
- Invalid master tag data
- Invalid tag data
- Unsupported type: ${property.type} ${currentPath}
AI-assisted analysis of hcengineering/platform@63e28dc964 (2026-08-29).
Data as JSON: /api/errors/a10c10fd80d31bec.
Report an issue: GitHub.