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#
- 2026-07-07 03:51:08 KST — Revision 25054 (bim_id 20418) 처리 시작,
AwsS3Manager구성 - 2026-07-07 03:51:11 KST —
REVISE-BEGIN로그 기록,runBimCompare호출 (formatType: svf2,previousFormatType: svf) - 2026-07-07 03:51:13 KST — Child process 에서
ForgeUtilsError: Invalid OTG manifest발생,INVALID_OTG_MANIFEST로 종료.REV1로 매핑되어REVISE-END status=error(elapsed_ms=3204) - 2026-07-07 03:58:14 KST — Revision 25056 (bim_id 20418) child process fork
- 2026-07-07 03:58:17 KST — 동일한
ForgeUtilsError: Invalid OTG manifest재현,REVISE-END status=error(elapsed_ms=2985) - 2026-07-07 03:58:18 ~ 03:58:23 KST — 별개 BIM (
bim_id: 20420, revision 25055) 은 정상 처리 후REVISE-END status=success
Error Log#
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.setupEventHandlers 의 process.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:177—run→runBimCompare - Child process fork:
applications/agents/packages/base/src/manager/child-process.manager.ts:74—fork(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 레벨로 흘려보낸다.
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 를 매핑한다.
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 으로 다운그레이드한다.
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 에서
ForgeUtilsErrorthrow → stderr 출력 (본 클러스터 시그니처) → 부모가 IPC 로 error code 를 수신 → REV1 로 매핑 → revision 이error상태로 종료.
Log Evidence#
Datadog query (재현):
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):
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'
}
부모 프로세스가 관측한 결과 (같은 타임스탬프):
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 요약 (첫 번째 발생):
{
"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):
{
"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"
}
파라미터 (첫 번째 발생):
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:177의run진입점.
단기 개선 (1주 이내)#
ForgeAgentErrorCodeenum 에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: success및progress: 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 데이터 문제 트렌드):
sum:trace.node.request.errors{service:cupixworks-any-bimrevision-agent} by {env}.as_count()
- BIM revision agent 실패 로그 카운트 (본 클러스터 시그니처):
logs("service:cupixworks-any-bimrevision-agent status:error \"INVALID_OTG_MANIFEST\"").index("*").rollup("count").by("env")
- 부모 프로세스가 관측한 mapped REV1 카운트 (매핑 결함 노출용):
logs("service:cupixworks-any-bimrevision-agent \"Unmapped forge error code detected\"").index("*").rollup("count").by("env")
- REVISE-END status=error 비율 (성공률과 함께 대시보드 표시 권장):
logs("service:cupixworks-any-bimrevision-agent \"REVISE-END\" \"status\\\":\\\"error\"").index("*").rollup("count").by("env")
알림 권장:
- 동일
bim_id에 대해 5분 창 내INVALID_OTG_MANIFEST2회 이상 발생 시 warn (upstream 데이터 문제 후보) Unmapped forge error code detected가 시간당 10회 이상이면 매퍼 업데이트 필요 알림
Risk Assessment#
- Risk level: low — 특정 BIM (
bim_id: 20418) 두 revision 에 한정, 같은 시간대 다른 BIM 은 성공. 서비스 전반 영향 없음. - 예상 복잡도: trivial (즉시 조치는 ops 재변환), standard (매퍼/enum 확장 및 관측성 개선).