ES /docs

ChildProcessManager::setupEventHandlers | Child process stderr: AssertionError [ForgeAgentError]: Mu

RCA: Derivative not found for modelId: 11 @ EntityMap.derivativesload()

Overview#

What Happened#

2026-05-27 09:17:56 UTC에 cupixworks-any-bimrevision-agent 서비스에서 BIM revision 비교 작업 중 ForgeAgentError (code 514)가 발생했다. @cupix/forge-agents 패키지의 EntityMap.load() 메서드가 Forge manifest에서 modelId 11에 해당하는 SVF derivative를 찾지 못해 assertion failure가 발생하고, 이것이 critical error로 분류되어 전체 revision 비교 작업이 중단되었다.

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 (compiled)
runtime Node.js (child process via @cupix/forge-agents@10.98.0)
env production, us-west-2

Affected Teams#

Team / Domain Error Count Impact
exyte (BIM Revision) 2 bim_id 18046의 V2→V3 revision 비교 실패, 13,684개 element 업데이트 미반영

Timeline#

  1. 2026-05-27 09:16:32 UTC — BimRevisionService 시작 (bimRevisionId: 23760, bimId: 18046)
  2. 2026-05-27 09:16:50 UTC — REVISE-BEGIN, BIM 비교 시작
  3. 2026-05-27 09:17:56 UTC — EntityMap.load()에서 modelId 11 derivative 조회 실패, ForgeAgentError 514 발생
  4. 2026-05-27 09:17:56 UTC — Critical Forge error로 분류, revision 상태 Error로 전환
  5. 2026-05-27 09:17:57 UTC — 작업 공간 정리, REVISE-END (status: error)

Error Log#

Datadog Logs

text
ChildProcessManager::setupEventHandlers | Child process stderr: AssertionError [ForgeAgentError]: Must not be a nullable value: Derivative not found for modelId: 11 @ EntityMap.derivativesload()

Impact#

  • Service: cupixworks-any-bimrevision-agent
  • Team: exyte
  • 발생 횟수: 2
  • 최초 발생: 2026-05-27T09:17:56.519Z
  • 최근 발생: 2026-05-27T09:17:56.521Z

Root Cause Summary#

Forge manifest에서 modelId 11에 해당하는 SVF derivative가 존재하지 않아 EntityMap.load() 내부의 CPAssert.assertDefined() assertion이 실패했다. 이 에러는 Autodesk Forge의 model derivative API에서 해당 모델의 변환(translation)이 아직 완료되지 않았거나, manifest에 해당 viewable이 등록되지 않은 상태에서 비교 작업이 시작된 것이 원인이다. @cupix/forge-agents 패키지는 derivative 조회 실패를 복구 불가능한 assertion error로 처리하며, ForgeErrorMapper에서 이를 ignorable error로 분류하지 않아 전체 작업이 중단된다.

Technical Analysis#

Code Path#

  • Entry point: bim-revision-service.ts:177runBimCompare() 호출
  • Child process 실행: bim-compare.manager.ts:65childProcessManager.execute() via IPC
  • Forge extract 호출: bim-compare.process.ts:72ForgeAgent.extract() 실행
  • Failure point: entity-map.js:86 (compiled) — CPAssert.assertDefined(derivative, ...) assertion 실패

1. BimRevisionService에서 비교 시작:

packages/cupix-tesla-bim-revision-agent/src/bim-revision-service.ts:177typescript
await this.runBimCompare(this.cpBimRevision, this.cpPreviousBimRevision);

2. BimCompareManager가 child process로 작업 위임:

packages/cupix-tesla-bim-revision-agent/src/manager/bim-compare.manager.ts:64-78typescript
try {
    const result = await this.childProcessManager.execute<ForgeAgent.Result>('execute', params);
    logger.debug('BimCompareManager::execute | completed successfully');
    return result;
} catch (error) {
    logger.error('BimCompareManager::execute | error:', error);
    const errorCode = ErrorCode.Agent.BimRevisionExtractorExecute;
    if (this.setErrorCode) {
        this.setErrorCode(errorCode);
    }
    throw error;
}

3. Child process에서 ForgeAgent.extract 실행:

packages/cupix-tesla-bim-revision-agent/src/process/bim-compare.process.ts:72-81typescript
const result: ForgeAgent.Result = await ForgeAgent.extract(params.apiConfig, params.urn, {
    region: params.region,
    extractRoom: false,
    extractMeta: false,
    extractCompare: {
        urn: params.previousUrn,
        region: params.previousRegion,
        query: params.query
    }
});

4. EntityMap.load()에서 derivative 조회 실패 (compiled JS):

node_modules/@cupix/forge-agents/extractor/compare-extractor/entity-map.js:83-86javascript
const derivative = modelId == null
    ? this.manifest_.default3dDerivative
    : this.derivatives.find((d) => scope.getModelId(d) === modelId);
CPAssert.assertDefined(derivative, ForgeAgentErrorCode.DERIVATIVE_IS_NOT_DEFINED,
    `Derivative not found for modelId: ${modelId} @ EntityMap.derivativesload()`);

modelId가 11로 전달되었으나 this.derivatives 배열에서 해당 modelId를 가진 derivative를 찾지 못해 undefined가 반환되고, assertDefinedForgeAgentError (code 514)를 throw한다.

5. Error propagation — ForgeErrorMapper가 critical error로 분류:

packages/cupix-tesla-bim-revision-agent/src/util/forge-error-mapper.ts:20-22typescript
private static ignorableErrorCodes: Set<ForgeAgentErrorCode> = new Set([
    ForgeAgentErrorCode.ROOM_EXT_ROOM_MAKER_IS_NOT_DEFINED
]);

DERIVATIVE_IS_NOT_DEFINED (514)는 ignorable set에 포함되지 않아 critical error로 처리된다.

packages/cupix-tesla-bim-revision-agent/src/bim-revision-service.ts:663-671typescript
if (forgeErrorCode) {
    if (ForgeErrorMapper.isIgnorableError(forgeErrorCode)) {
        logger.warn('BimRevisionService::runBimCompare | Ignorable Forge error detected...');
    } else {
        const errorCode = ForgeErrorMapper.mapForgeErrorToRevisionError(forgeErrorCode);
        logger.error('BimRevisionService::runBimCompare | Critical Forge error detected...');
        this.setErrorCode(errorCode);
        throw new Error(`BimRevisionService::runBimCompare | Forge error: ${forgeErrorCode} - ${forgeErrorMessage}`);
    }
}

Log Evidence#

사용한 Datadog 쿼리:

text
service:cupixworks-any-bimrevision-agent status:error @environment:production
text
service:cupixworks-any-bimrevision-agent "Derivative not found"

에러 발생 시 전체 로그 흐름:

text
2026-05-27 18:16:32 [info] BaseService::runByMessage | id: 23760
2026-05-27 18:16:32 [info] BimRevisionService::run | si_trace_id: a198b446-4fde-4f3e-8d38-5a934fdf3904
2026-05-27 18:16:32 [info] BimRevisionService::loadAllElements | begin - bimId: 18046, facilityKey: 5k6vfs
2026-05-27 18:16:50 [info] BimRevisionService::REVISE-BEGIN | {...}
2026-05-27 18:17:56 [error] ChildProcessManager::setupEventHandlers | Child process stderr: AssertionError [ForgeAgentError]: Must not be a nullable value: Derivative not found for modelId: 11 @ EntityMap.derivativesload()
2026-05-27 18:17:56 [error] BimRevisionService::runBimCompare | Critical Forge error detected - forgeErrorCode: 514, mapped to revisionErrorCode: REV514
2026-05-27 18:17:56 [error] BimRevisionService::run | error: "BimRevisionService::runBimCompare | Forge error: 514 - Must not be a nullable value: Derivative not found for modelId: 11 @ EntityMap.derivativesload()"
2026-05-27 18:17:56 [warn] CPBimRevision::validateBimComparerResult | forgeErrorMessage: Must not be a nullable value: Derivative not found for modelId: 11 @ EntityMap.derivativesload()
2026-05-27 18:17:57 [info] BimRevisionService::REVISE-END | {...status: "error", counts all zero...}

Full stack trace:

text
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 process.processTicksAndRejections (node:internal/process/task_queues:95:5)
    at async CompareExtractor.collectPrevEntities (/tmp/agent/dist/.../compare-extractor.js:991:13)
    at async CompareExtractor.compare (/tmp/agent/dist/.../compare-extractor.js:91:38)
    at async extractComparison (/tmp/agent/dist/.../app.js:133:20)
    at async Object.extract (/tmp/agent/dist/.../app.js:82:25)
    at async BimCompareProcess.processMessage (/tmp/agent/dist/process/bim-compare.process.cjs:6435:16)

에러가 CompareExtractor.collectPrevEntities에서 발생한 것으로 보아, 이전 revision(V2)의 manifest에서 modelId 11을 찾으려 한 것이다. 현재 revision(V3)의 src_forge_urn에 version=11이 인코딩되어 있으므로, 새 revision에는 11개의 viewable model이 있지만, 이전 revision(V2)의 manifest에는 modelId 11이 존재하지 않는 상태다.

Key identifiers:

  • bim_id: 18046
  • facilityKey: 5k6vfs
  • src_revision_id: 23760 (V3), prev_revision_id: 21803 (V2)
  • src_forge_urn: version=11, prev_forge_urn: version=2
  • cp_elements_count: 13,684 (created: 12,337, deleted: 1,347)
  • Elapsed time: ~85 seconds

Hypotheses Considered#

# Hypothesis Evidence for Evidence against Verdict
H1 V3에 새 model이 추가되어 V2 manifest에 존재하지 않는 modelId 11을 조회하려 함 src_forge_urn version=11, prev_forge_urn version=2; collectPrevEntities에서 실패; 12,337개 created elements는 새 model 추가를 시사 Confirmed
H2 Forge derivative 변환(translation)이 완료되지 않은 상태에서 비교 시작 derivative 관련 assertion failure 만약 translation 미완료라면 manifest 자체를 로드 못하는 다른 에러가 발생할 것; stack trace가 manifest는 정상 로드 후 find에서 실패 Rejected
H3 Forge API 일시적 장애로 manifest 데이터 불완전 반환 동일 시간대 다른 revision 작업들은 정상 수행됨 (23752, 23758, 23759); 단일 bim_id에서만 발생 Rejected

Fix Recommendation#

즉시 조치 (Critical)#

  • @cupix/forge-agents 패키지의 entity-map.js:83-86에서 derivative를 찾지 못할 때 assertion 대신 graceful handling이 필요하다.
  • 다만 이것은 npm 패키지 내부이므로, 에이전트 서비스 측에서 이 에러를 처리하는 것이 더 현실적이다.
  • forge-error-mapper.ts:20-22에서 DERIVATIVE_IS_NOT_DEFINED (514)를 ignorable set에 추가하거나, 또는 partial failure로 처리하여 해당 modelId만 건너뛰고 나머지 비교를 계속하도록 변경한다.
  • 파일: packages/cupix-tesla-bim-revision-agent/src/util/forge-error-mapper.ts:20

단기 개선 (1주 이내)#

  • CompareExtractor.collectPrevEntities 호출 전에 이전 revision의 manifest에 포함된 modelId 목록을 확인하고, 새 revision에만 존재하는 modelId는 비교 대상에서 제외하는 전처리 로직 추가.
  • bim-revision-service.tsrunBimCompare params 생성 시, query.entities에서 이전 revision에 없는 modelId를 가진 entity를 필터링하는 방안 검토.

장기 개선 (재발 방지)#

  • @cupix/forge-agents 패키지에서 derivative 미발견 시 assertion 대신 modelIdsFailedToLoad 배열에 추가하고 나머지 model은 정상 처리하도록 partial-failure 패턴 적용 (패키지 업스트림 변경 필요).
  • Revision 비교 시 model 구조 변경(model 추가/삭제) 시나리오에 대한 통합 테스트 추가.

Monitoring#

  • DERIVATIVE_IS_NOT_DEFINED 에러 빈도 추적:
text
service:cupixworks-any-bimrevision-agent "Derivative not found for modelId" status:error
  • Forge error code 514 발생률 대시보드:
text
service:cupixworks-any-bimrevision-agent "Critical Forge error detected" "514"

Risk Assessment#

  • Risk level: medium
  • 예상 복잡도: standard — ForgeErrorMapper에 ignorable 추가는 간단하지만, partial failure 처리를 올바르게 구현하려면 비교 결과 무결성 검증이 필요하다. 해당 에러는 model 구조 변경(viewable 추가) 시 재발할 수 있다.