ChildProcessManager::setupEventHandlers | Child process stderr: at RevitEntityMap.load (/tmp/age
RCA: RevitEntityMap.load — Derivative not found for modelId: 11
Overview#
What Happened#
2026-05-27 09:17:56 UTC에 cupixworks-any-bimrevision-agent 서비스에서 BIM revision 비교 작업 중 RevitEntityMap.load()가 이전 버전(V2)의 manifest에서 modelId 11에 대한 derivative를 찾지 못해 AssertionError가 발생했다. 해당 모델은 V2 이후에 추가된 것으로, 이전 버전에는 존재하지 않는 modelId를 조회한 것이 원인이다.
Quick Facts#
| Field | Value |
|---|---|
| exception.class | AssertionError [ForgeAgentError] |
| exception.message | Must not be a nullable value: Derivative not found for modelId: 11 @ EntityMap.derivativesload() |
| top_frame | entity-map.js:97 (v10.98.0) |
| runtime | Node.js (child process via BimCompareProcess) |
| deploy | @cupixapps/forge-agents@10.98.0 |
| env | production, us-west-2 |
Affected Teams#
| Team / Domain | Error Count | Impact |
|---|---|---|
| exyte | 2 | BIM revision 비교(V2→V3) 실패, bim_id 18046의 revision 결과 미생성 |
Timeline#
- 09:16:31Z — BimRevisionService 시작 (bim_id: 18046, src_revision: V3, prev_revision: V2)
- 09:16:50Z — runBimCompare 시작 (entities: 12,337, checkExistence: 1,347)
- 09:17:56Z —
RevitEntityMap.load()실패 — derivative not found for modelId: 11 - 09:17:56Z — BimRevisionService 종료 (forgeErrorCode: 514, mapped to REV514)
Error Log#
ChildProcessManager::setupEventHandlers | Child process stderr: at RevitEntityMap.load (/tmp/agent/dist/node_modules/.pnpm/@cupixapps+forge-agents@10.98.0_@cupixapps+forge-utils@10.98.0_axios@1.16.1_commander@3_4afb3908afc424afaaf209aa519ab2ca/node_modules/@cupixapps/forge-agents/extractor/compare-extractor/entity-map.js:97:33)
Impact#
- Service:
cupixworks-any-bimrevision-agent - Team: exyte
- 발생 횟수: 2
- 최초 발생: 2026-05-27T09:17:56.520Z
- 최근 발생: 2026-05-27T09:17:56.521Z
Root Cause Summary#
CompareExtractor.collectPrevEntities()가 현재 버전(V3, source URN version 11)의 entity 목록에서 추출한 modelId: 11을 이전 버전(V2, prev URN version 2)의 RevitEntityMap에 로드하려고 시도했다. 이전 버전의 Forge manifest에는 modelId 11에 해당하는 derivative가 존재하지 않으므로(해당 모델은 V2 이후에 추가됨), assertDefined가 실패하여 ForgeAgentError(code 514)가 throw되었다. collectPrevEntities에는 target model loading과 달리 try/catch가 없어, 단일 model load 실패가 전체 비교 작업을 중단시킨다.
Technical Analysis#
Code Path#
- Entry point:
child-process.manager.ts:138-141— stderr handler가 child process의 에러 출력을 감지 BimCompareProcess.execute→BimCompareProcess.processMessage→CompareExtractor.collectPrevEntities- Failure point:
entity-map.js:97(v10.98.0) —assertDefined(derivative, ...)assertion 실패
const derivative = modelId == null
? this.manifest_.default3dDerivative
: this.derivatives.find((d) => scope.getModelId(d) === modelId);
cpassert_1.CPAssert.assertDefined(derivative, forge_agent_error_code_1.ForgeAgentErrorCode.DERIVATIVE_IS_NOT_DEFINED, `Derivative not found for modelId: ${modelId} @ EntityMap.derivativesload()`);
this.derivatives는 이전 버전(V2) manifest의 derivative 목록이다. V2에는 modelId 11이 존재하지 않으므로 find()가 undefined를 반환하고, assertDefined가 throw한다.
async collectPrevEntities(query, entityMap) {
const loaded = { entities: [], modelIds: [] };
const entityGroups = CompareExtractor.groupEntitiesByModelId(query.entities);
const bimMat = bim_meta_utils_1.BIMMetaUtils.getBIMMat(query.bimSetting);
for (const group of entityGroups) {
await entityMap.load(group.modelId, { // NO try/catch here
bimMat: bimMat,
levels: query.levels,
loadBounds: true,
propNames: query.propNames,
customPropNames: query.customPropNames,
...
filter: { dbIds: group.dbIds }
});
// ...
}
return loaded;
}
비교 대상: target model loading(line 122-141)에는 try/catch가 존재하여 실패한 모델을 modelIdsFailedToLoad에 추가하고 continue하지만, collectPrevEntities(source/prev loading)에는 동일한 보호가 없다.
// load target model
try {
await targetData.entityMap.load(targetModelId, { ... });
}
catch (_err) {
cplogger_1.default.debug(` Failed to load model #${targetModelId}: `);
result.modelIdsFailedToLoad.push({
modelId: targetModelId,
error: forge_agent_error_1.ForgeAgentError.getError(_err, ...)
});
continue; // gracefully skip failed model
}
this.process.stderr?.on('data', (data: Buffer) => {
const text = data.toString();
logger.error(`ChildProcessManager::setupEventHandlers | Child process stderr: ${text}`);
});
Log Evidence#
사용한 Datadog 쿼리:
service:cupixworks-any-bimrevision-agent status:error @environment:production
service:cupixworks-any-bimrevision-agent @environment:production @bim_id:18046
핵심 에러 로그 (09:17:56.519Z-09:17:56.523Z):
AssertionError [ForgeAgentError]: Must not be a nullable value: Derivative not found for modelId: 11 @ EntityMap.derivativesload()
at Object.assertDefined (/tmp/agent/dist/node_modules/.pnpm/@cupixapps+forge-agents@10.98.0_.../node_modules/@cupixapps/forge-agents/cpassert.js:27:19)
at RevitEntityMap.load (/tmp/agent/dist/node_modules/.pnpm/@cupixapps+forge-agents@10.98.0_.../node_modules/@cupixapps/forge-agents/extractor/compare-extractor/entity-map.js:97:33)
at async CompareExtractor.compare (/tmp/agent/dist/.../compare-extractor.js:91:38)
at async Object.extract (/tmp/agent/dist/.../app.js:82:25)
at async extractComparison (/tmp/agent/dist/.../app.js:133:20)
at async CompareExtractor.collectPrevEntities (/tmp/agent/dist/.../compare-extractor.js:991:13)
at async BimCompareProcess.processMessage (/tmp/agent/dist/process/bim-compare.process.cjs:6435:16)
at async BimCompareProcess.execute (/tmp/agent/dist/process/bim-compare.process.cjs:6459:22) {
errorCode: 514
}
서비스 레벨 에러 로그:
{
"message": "BimRevisionService::runBimCompare | Critical Forge error detected",
"forgeErrorCode": 514,
"mapped_to": "REV514"
}
BimRevisionService::run | error: "BimRevisionService::runBimCompare | Forge error: 514 - Must not be a nullable value: Derivative not found for modelId: 11 @ EntityMap.derivativesload()"
작업 컨텍스트 (같은 trace에서 확인):
{
"bim_id": 18046,
"src_revision_id": 23760,
"src_revision_name": "V3",
"prev_revision_id": 21803,
"prev_revision_name": "V2",
"facilityKey": "5k6vfs",
"team_domain": "exyte",
"src_forge_urn": "dXJuOmFkc2sud2lwZW1lYTpmcy5maWxlOnZmLk5UZVBmaVFHVEJPV0EtX29ZZV9YVlE_dmVyc2lvbj0xMQ==",
"prev_forge_urn": "dXJuOmFkc2sud2lwZW1lYTpmcy5maWxlOnZmLk5UZVBmaVFHVEJPV0EtX29ZZV9YVlE_dmVyc2lvbj0y",
"formatType": "svf2",
"region": "EMEA",
"cp_elements_count": 13684,
"cp_elements_created_count": 12337,
"cp_elements_deleted_count": 1347,
"elapsed_ms": 84853
}
source URN은 version 11, previous URN은 version 2로 — 대규모 버전 갭(9개 버전 차이)이 존재한다.
Hypotheses Considered#
| # | Hypothesis | Evidence for | Evidence against | Verdict |
|---|---|---|---|---|
| H1 | 이전 버전(V2)에 존재하지 않는 modelId 11을 collectPrevEntities에서 조회하여 derivative 없음 |
에러 메시지 "Derivative not found for modelId: 11", source URN이 version 11이고 prev URN이 version 2 (9 버전 차이), collectPrevEntities가 현재 entities의 modelId로 이전 manifest를 조회하는 코드 구조 |
— | Confirmed |
| H2 | Forge/APS API 일시적 장애로 derivative 로드 실패 | — | 에러 메시지가 명확히 "Derivative not found" (네트워크 에러와 다름), 같은 시간대 다른 작업들은 정상 완료, errorCode 514는 DERIVATIVE_IS_NOT_DEFINED (네트워크 에러 코드와 다름) | Rejected |
| H3 | propDb 로드 실패 (line 97이 propDb assertion) | Stack trace가 entity-map.js:97을 가리킴 | 에러 메시지가 "Derivative not found for modelId: 11 @ EntityMap.derivativesload()"이며 errorCode가 514 (DERIVATIVE_IS_NOT_DEFINED). v10.98.0에서는 derivative assertion이 line 97에 위치 (v10.21.0에서는 line 86) | Rejected |
Fix Recommendation#
즉시 조치 (Critical)#
collectPrevEntities (compare-extractor.js 내)에 target model loading과 동일한 try/catch 패턴을 적용해야 한다. 이전 버전 manifest에 존재하지 않는 modelId에 대해 load 실패 시, 해당 그룹을 건너뛰고 작업을 계속 진행하도록 수정한다.
- 파일:
@cupixapps/forge-agents패키지 내extractor/compare-extractor/compare-extractor.ts(또는 .js) - 위치:
collectPrevEntities메서드,entityMap.load()호출부 (line 358 부근) - 방향:
entityMap.load()호출을 try/catch로 감싸고, DERIVATIVE_IS_NOT_DEFINED 에러 발생 시 해당 modelId 그룹을 skip하면서 로그를 남긴다. 이전 버전에 없는 모델의 entity들은 "새로 추가된 것"으로 처리한다.
단기 개선 (1주 이내)#
collectPrevEntities호출 전에 source entities의 modelId 목록과 previous manifest의 derivative modelId 목록을 비교하여, 이전 버전에 존재하지 않는 modelId의 entity들을 사전 필터링하는 로직을 추가한다.- 대규모 버전 갭(예: 9개 버전 이상 차이) 시 경고 로그를 추가하여 운영자가 인지할 수 있도록 한다.
장기 개선 (재발 방지)#
@cupixapps/forge-agents패키지의collectPrevEntities와 target model loading 간 에러 핸들링 패턴을 일관되게 통일한다.- BIM revision 비교 시 버전 간 모델 구조 변경(모델 추가/삭제)을 명시적으로 처리하는
modelComparison매핑 로직을collectPrevEntities에도 적용한다 (현재는compare메서드의 target loading에만 적용).
Monitoring#
- ForgeAgentError code 514 발생 빈도 모니터링:
service:cupixworks-any-bimrevision-agent "forgeErrorCode: 514" @environment:production
- 버전 갭이 큰 BIM revision 작업 추적:
service:cupixworks-any-bimrevision-agent "runBimCompare" @environment:production
Risk Assessment#
- Risk level: medium
- 예상 복잡도: standard —
@cupixapps/forge-agentsnpm 패키지 내부 수정이 필요하며, 패키지 빌드/배포 사이클을 따라야 한다. 코드 변경 자체는 try/catch 추가로 단순하나, 이전 버전에 없는 entity를 "신규"로 처리하는 비즈니스 로직 결정이 필요하다.