ES /docs

ChildProcessManager::setupEventHandlers | Child process stderr: at BIMSVF2Manifest.init (/tmp/ag

RCA: ChildProcessManager stderr — ForgeUtilsError: Invalid OTG manifest

Overview#

What Happened#

2026-07-07 03:51 ~ 03:58 KST 사이에 cupixworks-any-bimrevision-agent (tenant cupix, team gilbaneco, us-west-2) 에서 BIM revision 비교 작업 2건이 ForgeUtilsError: Invalid OTG manifest 로 실패했다. Autodesk Forge/APS 가 반환한 SVF2 OTG manifest 파일이 검증에 실패했기 때문이며, 두 실패 모두 동일한 BIM (bim_id: 20418) 의 서로 다른 revision (25054, 25056) 에서 발생했다. 사용자 관점에서는 두 revision 이 bim_comparison_state=error 로 상태 코드 REV1 (UNKNOWN) 을 받았다.

Quick Facts#

Field Value
exception.class ForgeUtilsError
exception.message Invalid OTG manifest
exception.errorCode INVALID_OTG_MANIFEST
top_frame @cupixapps/forge-utils/convert-utils/svf2/svf2-manifest.js:77:30 (BIMSVF2Manifest.init)
runtime Node.js child process (fork), forge-utils@10.98.0, forge-agents@10.98.0
env production, region us-west-2, tenant cupix, team gilbaneco

Affected Teams#

Team / Domain Error Count Impact
gilbaneco (bim_id 20418) 2 BIM revision 비교 2건 실패 (revision 25054, 25056), bim_comparison_state=error (REV1)

Timeline#

  1. 2026-07-07 03:51:08 KST — Revision 25054 (bim_id 20418) 처리 시작, AwsS3Manager 구성
  2. 2026-07-07 03:51:11 KSTREVISE-BEGIN 로그 기록, runBimCompare 호출 (formatType: svf2, previousFormatType: svf)
  3. 2026-07-07 03:51:13 KST — Child process 에서 ForgeUtilsError: Invalid OTG manifest 발생, INVALID_OTG_MANIFEST 로 종료. REV1 로 매핑되어 REVISE-END status=error (elapsed_ms=3204)
  4. 2026-07-07 03:58:14 KST — Revision 25056 (bim_id 20418) child process fork
  5. 2026-07-07 03:58:17 KST — 동일한 ForgeUtilsError: Invalid OTG manifest 재현, REVISE-END status=error (elapsed_ms=2985)
  6. 2026-07-07 03:58:18 ~ 03:58:23 KST — 별개 BIM (bim_id: 20420, revision 25055) 은 정상 처리 후 REVISE-END status=success

Error Log#

Datadog Logs

text
ChildProcessManager::setupEventHandlers | Child process stderr:     at BIMSVF2Manifest.init (/tmp/agent/dist/node_modules/.pnpm/@cupixapps+forge-utils@10.98.0_axios@1.16.1_commander@3.0.2_fflate@0.8.3_rxjs@7.8.2_three@0.170.0_ws@8.21.0/node_modules/@cupixapps/forge-utils/convert-utils/svf2/svf2-manifest.js:77:30)

Impact#

  • Service: cupixworks-any-bimrevision-agent
  • Team: gilbaneco
  • 발생 횟수: 2
  • 최초 발생: 2026-07-07 03:51:13 KST
  • 최근 발생: 2026-07-07 03:58:17 KST

Root Cause Summary#

Autodesk Forge/APS 가 bim_id 20418 의 두 revision (25054, 25056) 에 대해 반환한 OTG (SVF2 optimized) manifest 가 forge-utils 의 ModelDataManifestHelper.validateOtgManifest 검증을 통과하지 못했다. 결과적으로 BIMSVF2Manifest.init 에서 ForgeUtilsError('Invalid OTG manifest') (errorCode: 'INVALID_OTG_MANIFEST') 가 throw 되어 child process 가 종료됐고, 이 stderr 출력이 부모 프로세스 ChildProcessManager.setupEventHandlersprocess.stderr.on('data') 리스너를 통해 그대로 logger.error 로 흘러나온 것이 이번 클러스터의 시그니처다. 즉 stderr 로그는 원인이 아니라 증상이며, 실제 실패 원인은 upstream (Autodesk APS) 이 반환한 SVF2 model derivative 의 OTG manifest 손상/미완성이다. 추가로, INVALID_OTG_MANIFEST 라는 error code 자체가 ForgeAgentErrorCode enum 에 정의되어 있지 않아 ForgeErrorMapper.mapForgeErrorToRevisionError 가 이를 UNKNOWN (REV1) 으로 강등하고 있어 사용자에게 노출되는 에러 코드가 실제 원인과 매핑되지 않는 2차 문제도 존재한다.

Technical Analysis#

Code Path#

  • Entry point: applications/agents/packages/cupix-tesla-bim-revision-agent/src/bim-revision-service.ts:177runrunBimCompare
  • Child process fork: applications/agents/packages/base/src/manager/child-process.manager.ts:74fork(actualScriptPath, ...)
  • stderr listener attach: applications/agents/packages/base/src/manager/child-process.manager.ts:138-141
  • Failure point (upstream): @cupixapps/forge-utils/convert-utils/svf2/svf2-manifest.js:77:30@cupixapps/forge-utils/server-utils/model-data.js:44:19 (ModelDataManifestHelper.validateOtgManifest)
  • Mapping downgrade: applications/agents/packages/cupix-tesla-bim-revision-agent/src/util/forge-error-mapper.ts:33-39

부모 프로세스 ChildProcessManager 는 fork 된 child 의 stderr 를 그대로 error 레벨로 흘려보낸다.

applications/agents/packages/base/src/manager/child-process.manager.ts:138-141typescript
this.process.stderr?.on('data', (data: Buffer) => {
    const text = data.toString();
    logger.error(`ChildProcessManager::setupEventHandlers | Child process stderr: ${text}`);
});

Child process (BimCompareProcess) 는 forge-agents 를 호출하고, forge-agents 는 forge-utils 의 SVF2 manifest 로더로 이어진다. forge-utils 는 Forge/APS derivative 서비스에서 받은 OTG manifest JSON 을 검증한 뒤, 검증 실패 시 errorCode: 'INVALID_OTG_MANIFEST' 를 가진 ForgeUtilsError 를 던진다 (log evidence 의 stack trace 참고).

부모 프로세스의 BimRevisionService::runBimCompare 는 그 결과를 받아 error code 를 매핑한다.

applications/agents/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 - forgeErrorCode: %s, message: %s', forgeErrorCode, forgeErrorMessage);
    } else {
        const errorCode = ForgeErrorMapper.mapForgeErrorToRevisionError(forgeErrorCode);
        logger.error('BimRevisionService::runBimCompare | Critical Forge error detected - forgeErrorCode: %s, mapped to revisionErrorCode: %s', forgeErrorCode, errorCode);
        this.setErrorCode(errorCode);
        throw new Error(`BimRevisionService::runBimCompare | Forge error: ${forgeErrorCode} - ${forgeErrorMessage}`);
    }
}

매퍼는 ForgeAgentErrorCode enum 에 해당 값이 존재하지 않으면 UNKNOWN 으로 다운그레이드한다.

applications/agents/packages/cupix-tesla-bim-revision-agent/src/util/forge-error-mapper.ts:33-39typescript
static mapForgeErrorToRevisionError(forgeErrorCode: ForgeAgentErrorCode | any): string {
    if (Object.values(ForgeAgentErrorCode).includes(forgeErrorCode)) {
        return ErrorCode.Revision.statusCode(forgeErrorCode);
    }
    logger.warn('ForgeErrorMapper::mapForgeErrorToRevisionError | Unmapped forge error code detected - forgeErrorCode: %s, type: %s, mapping to UNKNOWN (REV1)', forgeErrorCode, typeof forgeErrorCode);
    return ErrorCode.Revision.statusCode(ForgeAgentErrorCode.UNKNOWN);
}
  • 기대 동작: Forge/APS 가 정상적인 OTG manifest 를 반환하고, BIMSVF2Manifest.init 이 성공, 비교 결과가 부모로 리턴되어 revision 이 Compared 상태가 된다.
  • 실제 동작: OTG manifest 검증 실패 → child 에서 ForgeUtilsError throw → stderr 출력 (본 클러스터 시그니처) → 부모가 IPC 로 error code 를 수신 → REV1 로 매핑 → revision 이 error 상태로 종료.

Log Evidence#

Datadog query (재현):

text
service:cupixworks-any-bimrevision-agent status:error "ChildProcessManager" @environment:production

Child stderr 원문 (2026-07-07 03:51:13 KST, si_trace_id 66f39544-213f-4283-9c57-e4a7cc0821bd):

text
ForgeUtilsError: Invalid OTG manifest
    at ModelDataManifestHelper.validateOtgManifest (/tmp/agent/dist/node_modules/.pnpm/@cupixapps+forge-utils@10.98.0_.../server-utils/model-data.js:44:19)
    at BIMSVF2Manifest.init (/tmp/agent/dist/node_modules/.pnpm/@cupixapps+forge-utils@10.98.0_.../convert-utils/svf2/svf2-manifest.js:77:30)
    at process.processTicksAndRejections (node:internal/process/task_queues:95:5)
    at async createEntityMap (.../forge-agents/extractor/entity-map-factory.js:16:5)
    at async CompareExtractor.loadEntityMap (.../forge-agents/extractor/compare-extractor/compare-extractor.js:304:27)
    at async CompareExtractor.compare (.../forge-agents/extractor/compare-extractor/compare-extractor.js:39:32)
    at async extractComparison (.../forge-agents/app.js:133:20)
    at async Object.extract (.../forge-agents/app.js:82:25)
    at async BimCompareProcess.execute (/tmp/agent/dist/process/bim-compare.process.cjs:6459:22)
    at async BimCompareProcess.processMessage (/tmp/agent/dist/process/bim-compare.process.cjs:6435:16) {
  errorCode: 'INVALID_OTG_MANIFEST'
}

부모 프로세스가 관측한 결과 (같은 타임스탬프):

text
CPBimRevision::validateBimComparerResult | forgeErrorCode: INVALID_OTG_MANIFEST
ForgeErrorMapper::mapForgeErrorToRevisionError | Unmapped forge error code detected - forgeErrorCode: INVALID_OTG_MANIFEST, type: string, mapping to UNKNOWN (REV1)
BimRevisionService::runBimCompare | Critical Forge error detected - forgeErrorCode: INVALID_OTG_MANIFEST, mapped to revisionErrorCode: REV1
BimRevisionService::run | error: "BimRevisionService::runBimCompare | Forge error: INVALID_OTG_MANIFEST - Invalid OTG manifest"

REVISE-END 요약 (첫 번째 발생):

json
{
  "bim_id": 20418,
  "src_revision_id": 25054,
  "prev_revision_id": 24909,
  "si_trace_id": "66f39544-213f-4283-9c57-e4a7cc0821bd",
  "elapsed_ms": 3204,
  "status": "error",
  "error_message": "BimRevisionService::runBimCompare | Forge error: INVALID_OTG_MANIFEST - Invalid OTG manifest"
}

REVISE-END 요약 (두 번째 발생, 03:58:17 KST):

json
{
  "bim_id": 20418,
  "src_revision_id": 25056,
  "prev_revision_id": 24909,
  "si_trace_id": "d5a97d44-f647-4ea5-af47-144a9ca1e0da",
  "elapsed_ms": 2985,
  "status": "error",
  "error_message": "BimRevisionService::runBimCompare | Forge error: INVALID_OTG_MANIFEST - Invalid OTG manifest"
}

파라미터 (첫 번째 발생):

text
formatType: svf2, region: US
urn: dXJuOmFkc2sud2lwcHJvZDpmcy5maWxlOnZmLnhZdHpMdHRtUnNDbzFhaDF1NVI1amc_dmVyc2lvbj00 (v4)
previousFormatType: svf (주의: 이전 revision 은 아직 svf, 신규는 svf2)
previousUrn: dXJuOmFkc2sud2lwcHJvZDpmcy5maWxlOnZmLnhZdHpMdHRtUnNDbzFhaDF1NVI1amc_dmVyc2lvbj0z (v3)

동일 agent 내 다른 BIM (bim_id: 20420) 은 같은 시간대에 정상 처리됨 (status: success, elapsed_ms=5088), 즉 agent 자체나 Forge/APS 전체 outage 는 아님.

Hypotheses Considered#

# Hypothesis Evidence for Evidence against Verdict
H1 Autodesk Forge/APS 가 특정 URN 의 OTG (SVF2) manifest 를 손상/미완성 상태로 반환 Stack trace 최상단이 ModelDataManifestHelper.validateOtgManifest, errorCode INVALID_OTG_MANIFEST; 동일 bim_id: 20418 의 두 revision 모두 실패; 같은 시각 다른 BIM (bim_id: 20420) 은 성공 → 특정 URN 만의 문제 Confirmed
H2 Child process fork 자체 실패 또는 IPC 오류 로그에 Child process forked with PID 성공, Child process ready 후 execute 진행됨. stderr 로 stack 이 나온 뒤 REVISE-END 가 정상적으로 기록됨 프로세스가 죽었다면 부모가 error code 를 IPC 로 받을 수 없음. 로그상 부모는 forgeErrorCode: INVALID_OTG_MANIFEST 를 정상 수신 Rejected
H3 cupixworks-any-bimrevision-agent service 전반의 장애 (상태 게시판의 svc:cupixworks-any-bimrevision-agent::unknown 인시던트) incident-board for-cluster 결과에 2026-07-06-svc-...unknown-1 인시던트 존재, 두 클러스터 포함 동일 agent 인스턴스가 같은 시간대에 bim_id: 20420 처리를 성공. 실패는 bim_id: 20418 에 한정 → service-wide 가 아닌 데이터-specific Rejected (as service-wide cause)
H4 previousFormatType=svf, formatType=svf2 로 되어 있어 이전 revision 이 SVF2 로 재변환되지 않은 상태에서 신규 SVF2 와 비교 시 신규 SVF2 의 OTG manifest 를 로드하다 실패 로그의 params: formatType: svf2, previousFormatType: svf. BIMSVF2Manifest.init 은 SVF2 (신규) 를 로드하는 지점 이전 SVF revision 은 로드까지 도달하지 못함(신규 SVF2 로드에서 먼저 실패). SVF2 자체의 OTG 가 손상됐다는 H1 과 상충하지 않는 보조 관측. 재변환 여부는 로그만으로 결정 불가 Inconclusive (보조 요인 가능)
H5 INVALID_OTG_MANIFEST 가 애초에 ForgeAgentErrorCode enum 에 미정의되어, unmap 되고 REV1 (UNKNOWN) 으로 흘러들어감 (에러 자체가 아닌 매핑 결함) ForgeErrorMapper::mapForgeErrorToRevisionError 가 "Unmapped forge error code detected ... mapping to UNKNOWN (REV1)" 를 명시적으로 warn. spec 파일에 INVALID_OTG_MANIFEST case 부재 (forge-error-mapper.spec.ts:25-90) 이것은 발생 원인이 아니라 관측성/UX 결함. 근본 원인 (H1) 을 대체하지 않음 Confirmed (secondary issue)

Fix Recommendation#

즉시 조치 (Critical)#

  • 재시도 (운영 조치 우선): bim_id 20418 의 revision 25054/25056 에 대해 Autodesk APS Model Derivative 서비스에서 SVF2 translation 을 재요청(재변환)하거나, APS 콘솔에서 해당 URN 의 derivative manifest 상태를 확인. 로그 근거상 원인이 upstream 데이터이므로 코드 변경만으로 즉시 해결되지 않는다. (코드 변경 불필요, ops 조치)
  • 참조 코드 경로: 재시도는 사용자/서비스 측 재큐잉(SQS cupix-tesla-bim-revision-agent-production) 으로 처리한다. applications/agents/packages/cupix-tesla-bim-revision-agent/src/bim-revision-service.ts:177run 진입점.

단기 개선 (1주 이내)#

  • ForgeAgentErrorCode enum 에 INVALID_OTG_MANIFEST 추가 및 별도 REV 코드 매핑 — 파일: @cupix/forge-agents 패키지의 forge-agent-error-code 정의 (외부 패키지, cupixworks 저장소 밖) 및 applications/agents/packages/cupix-tesla-bim-revision-agent/src/util/forge-error-mapper.ts:33. 그러면 사용자에게 UNKNOWN(REV1) 이 아닌 "upstream 모델 파일 손상" 계열의 명확한 코드가 노출되어 재변환/재업로드 안내가 자동화 가능하다.
  • stderr 로그 레벨 재검토applications/agents/packages/base/src/manager/child-process.manager.ts:138-141. child 가 catch-and-rethrow 로 이미 IPC 로 실패를 보고하는 경우, stderr 미러링은 warn 이 적절. 지금은 upstream 문제 하나가 부모의 logger.error 를 stack trace 라인 수만큼 폭발시켜 클러스터링을 왜곡한다. (팀 로거 컨벤션상 Error 객체는 그대로 넘겨야 하며 .message 추출 지양 — 메모리 노트 반영.)
  • 재시도 정책 도입 검토INVALID_OTG_MANIFEST 처럼 upstream 데이터 문제 계열은 짧은 backoff 후 1~2회 재시도가 유효할 수 있음(Forge 가 아직 derivative 를 준비 중일 가능성). 현재 코드 (bim-revision-service.ts:663-671) 는 즉시 throw 하고 REV1 을 확정한다.

장기 개선 (재발 방지)#

  • Autodesk APS derivative 상태 사전 확인: runBimCompare 진입 전에 GET /modelderivative/v2/designdata/{urn}/manifest 로 SVF2 파생물의 status: successprogress: complete 를 확인하고 미완성이면 pending 상태로 revision 을 유지 (Comparing 이 아닌 Waiting 상태 신설). 데이터 준비 완료 이벤트 후 재시도.
  • Upstream 에러 metric 세분화: forge error code 별 카운터를 Datadog metric 으로 발행하여 INVALID_OTG_MANIFEST 같은 upstream 이슈를 revision 실패율과 분리 추적.
  • 에러 카테고리 스키마: ForgeAgentErrorCode 를 (a) upstream 원본 손상, (b) upstream 일시 오류, (c) 우리 코드 결함, (d) 사용자 입력 오류 로 카테고리화하여 매퍼가 REV 코드뿐 아니라 재시도 가능 여부를 함께 반환하도록 개선.

Monitoring#

Datadog release-dashboard 용 timeseries 쿼리 예시:

  • INVALID_OTG_MANIFEST 발생률 (upstream 데이터 문제 트렌드):
text
sum:trace.node.request.errors{service:cupixworks-any-bimrevision-agent} by {env}.as_count()
  • BIM revision agent 실패 로그 카운트 (본 클러스터 시그니처):
text
logs("service:cupixworks-any-bimrevision-agent status:error \"INVALID_OTG_MANIFEST\"").index("*").rollup("count").by("env")
  • 부모 프로세스가 관측한 mapped REV1 카운트 (매핑 결함 노출용):
text
logs("service:cupixworks-any-bimrevision-agent \"Unmapped forge error code detected\"").index("*").rollup("count").by("env")
  • REVISE-END status=error 비율 (성공률과 함께 대시보드 표시 권장):
text
logs("service:cupixworks-any-bimrevision-agent \"REVISE-END\" \"status\\\":\\\"error\"").index("*").rollup("count").by("env")

알림 권장:

  • 동일 bim_id 에 대해 5분 창 내 INVALID_OTG_MANIFEST 2회 이상 발생 시 warn (upstream 데이터 문제 후보)
  • Unmapped forge error code detected 가 시간당 10회 이상이면 매퍼 업데이트 필요 알림

Risk Assessment#

  • Risk level: low — 특정 BIM (bim_id: 20418) 두 revision 에 한정, 같은 시간대 다른 BIM 은 성공. 서비스 전반 영향 없음.
  • 예상 복잡도: trivial (즉시 조치는 ops 재변환), standard (매퍼/enum 확장 및 관측성 개선).