ES /docs

SVF2GeometryWSSLoader — invalid OTG header from Forge

RCA: ChildProcessManager Invalid OTG header assertion

Overview#

What Happened#

2026-05-27 18:15:13 UTC에 cupixworks-any-bimrevision-agent 서비스에서 BIM revision 비교 child process가 SVF2 geometry 리소스를 파싱하는 중 "Invalid OTG header" assertion 에러가 stderr로 출력되었다. 이 에러는 @cupixapps/forge-utils 라이브러리의 SVF2GeometryWSSLoader.parseGeometryResource에서 발생했으며, 라이브러리 내장 retry 메커니즘에 의해 10초 대기 후 재시도에 성공하여 프로세스는 정상 계속되었다.

Quick Facts#

Field Value
exception.class AssertionError
exception.message Assertion failed - Invalid OTG header
top_frame @cupixapps/forge-utils/cpassert.js:30
runtime Node.js 20, @cupixapps/forge-agents@10.98.0, @cupixapps/forge-utils@10.98.0
env production, us-west-2

Timeline#

  1. 18:15:13 UTC — 첫 번째 "Invalid OTG header" assertion 발생 (geometry hash 歧ꀎ㱍哻贜뿩焲湀)
  2. 18:15:14 UTCparseWithRetry가 attempt 2로 재시도 시작 (10s 대기)
  3. 18:15:24 UTC — 재시도 성공: "Successfully parsed geometry resource"
  4. 18:53:27 UTC — 두 번째 "Invalid OTG header" assertion 발생 (geometry hash 漂䖽ꙮ쪦ጾ렧윓ꟻ殘￿)
  5. 18:53:43 UTC — 세 번째 "Invalid OTG header" + "Failed to decode geometry buffer" 발생 (geometry hash 攍₎デ奆갰恅᫤֍쩞닫)
  6. 18:53:54 UTC — 재시도 성공

Error Log#

Datadog Logs

text
ChildProcessManager::setupEventHandlers | Child process stderr:   msg: 'Assertion failed - Invalid OTG header',

Impact#

  • Service: cupixworks-any-bimrevision-agent
  • Team: exyte
  • 발생 횟수: 2 (cluster 기준; 실제 로그 라인은 9건 — 3회의 OTG header 에러 × 3 로그라인/에러)
  • 최초 발생: 2026-05-27T09:15:13.023Z
  • 최근 발생: 2026-05-27T09:15:13.026Z
  • 사용자 영향: 없음. 모든 경우 retry로 성공. BIM 비교 작업 자체는 이 에러와 무관한 별도 이유(REV141 excessive removal, derivative not found)로 실패하거나 성공 완료됨.

Root Cause Summary#

@cupixapps/forge-utilsSVF2GeometryWSSLoader.parseGeometryResource 함수가 Autodesk Forge 서버에서 수신한 geometry buffer를 디코딩할 때, 일부 geometry 리소스의 OTG 형식 헤더가 유효하지 않아 assertion이 발생한다. 이는 Forge 서버 측의 일시적 데이터 전송 이슈(corruption, CDN cache 문제, 또는 아직 완전히 전파되지 않은 데이터)로 인한 것으로, 라이브러리의 parseWithRetry 메커니즘이 10초 후 재시도하면 성공한다. 에러 로그가 발생하는 이유는 ChildProcessManager가 child process의 모든 stderr 출력을 logger.error() 레벨로 기록하기 때문이다.

Technical Analysis#

Code Path#

  • Entry point: BimRevisionService.runBimCompareBimCompareManager.execute (bim-revision-service.ts:647)
  • BimCompareManagerChildProcessManager.execute('execute', params)로 child process에 IPC 메시지 전송 (bim-compare.manager.ts:65)
  • Child process에서 ForgeAgent.extract(params.apiConfig, params.urn, {...}) 호출 (bim-compare.process.ts:72)
  • forge-agentsCompareExtractor.processTargetAndFillReportRevitEntityMap.loadGeometrySVF2Reader.loadGeometriesSVF2GeometryWSSLoader.loadSVF2GeometryWSSLoader.parseWithRetrySVF2GeometryWSSLoader.parseGeometryResource
  • Failure point: @cupixapps/forge-utils/cpassert.js:30 — OTG 바이너리 헤더 검증 실패
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의 모든 stderr 출력logger.error()로 기록한다. forge-utils 라이브러리의 내부 retry 로직에서 발생하는 일시적 assertion도 error 레벨로 로깅되어 Datadog에서 에러로 수집된다.

packages/cupix-tesla-bim-revision-agent/src/process/bim-compare.process.ts:67-81typescript
private async execute(params: BimComparerParams): Promise<ForgeAgent.Result> {
	try {
		this.log(`BimCompareProcess::execute | forge-agents version: ${forgeAgentsPkg.version}, spec_version: ${SpecVersion}`);
		this.log('BimCompareProcess::execute | start');

		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
			}
		});

이 코드에서 ForgeAgent.extract 호출 시 내부적으로 SVF2 geometry를 파싱하며, 특정 리소스에서 OTG 헤더 검증 실패가 발생한다. 단, 이 assertion은 parseWithRetry에 의해 catch되고 재시도 후 성공한다.

Log Evidence#

검색 쿼리:

text
service:cupixworks-any-bimrevision-agent status:error "Invalid OTG header"

OTG header assertion + retry 성공 시퀀스 (18:15:13 ~ 18:15:24):

text
[18:15:13] AssertionError: Assertion failed - Invalid OTG header
[18:15:13]   msg: 'Assertion failed - Invalid OTG header'
[18:15:13]   internalMsg_: 'Invalid OTG header'
[18:15:14] Retrying to parse geometry resource for hash 歧ꀎ㱍哻贜뿩焲湀, attempt 2 (waiting 10s)
[18:15:24] Successfully parsed geometry resource for hash 歧ꀎ㱍哻贜뿩焲湀, attempt 2

동일 패턴 반복 (18:53:27 ~ 18:53:54):

text
[18:53:27] AssertionError: Assertion failed - Invalid OTG header
[18:53:28] Retrying to parse geometry resource for hash 漂䖽ꙮ쪦ጾ렧윓ꟻ殘￿, attempt 2 (waiting 10s)
[18:53:38] Successfully parsed geometry resource for hash 漂䖽ꙮ쪦ጾ렧윓ꟻ殘￿, attempt 2
[18:53:43] Assertion failed - Invalid OTG header (hash 攍₎デ奆갰恅᫤֍쩞닫)
[18:53:43] Failed to decode geometry buffer (raw size: 4076, size: 0, zip: T)
[18:53:44] Retrying to parse geometry resource for hash 攍₎デ奆갰恅᫤֍쩞닫, attempt 2 (waiting 10s)
[18:53:54] Successfully parsed geometry resource for hash 攍₎デ奆갰恅᫤֍쩞닫, attempt 2

해당 시간대 BIM revision 작업 결과 — OTG error와 무관한 별도 이유로 실패:

text
[18:54:11] REVISE-END | bim_id:18047, src_revision_id:23763, status:"error", error_message:"validation failed (errorCode: REV141)"
[18:54:10] excessive removal detected - bimRevisionId: 23763, trigger: ratio 34.4% >= 15%

Hypotheses Considered#

# Hypothesis Evidence for Evidence against Verdict
H1 Forge 서버의 일시적 데이터 전송 문제로 OTG 헤더가 corrupt된 상태로 수신됨 retry 10초 후 동일 hash에서 성공 — 일시적 문제 확인; raw size: 4076, size: 0, zip: T는 디코딩 결과가 비어있음을 의미 Confirmed
H2 BIM 모델 자체에 손상된 geometry가 포함되어 있음 동일 hash에서 반복 실패할 수 있음 모든 경우 retry 성공 — 데이터 자체가 영구적으로 손상되었다면 재시도도 실패해야 함 Rejected
H3 ChildProcessManager의 stderr 로깅이 과도하게 error 레벨을 사용 child-process.manager.ts:140에서 모든 stderr를 logger.error()로 기록 — forge-utils의 내부 retry 경고도 error로 수집됨 Confirmed (보조 원인)

Fix Recommendation#

즉시 조치 (Critical)#

  • 없음. 이 에러는 forge-utils 라이브러리의 정상적인 retry 메커니즘으로 복구되며, BIM revision 작업에 실질적 영향이 없다.

단기 개선 (1주 이내)#

  • packages/base/src/manager/child-process.manager.ts:138-141에서 stderr 로깅 레벨을 logger.warn()으로 변경하는 것을 검토. child process stderr 출력이 반드시 critical error를 의미하지 않기 때문이다. 또는 특정 패턴("Retrying to parse", "Successfully parsed")을 감지하여 warn 레벨로 분류하는 로직 추가.

장기 개선 (재발 방지)#

  • ChildProcessManager에 stderr 로그 레벨 분류 로직 도입: assertion + retry 성공 패턴은 warn, process crash나 unhandled error는 error로 구분.
  • forge-utils 라이브러리에서 retry 관련 메시지를 stderr 대신 stdout 또는 IPC 메시지로 전달하도록 요청 (upstream dependency 변경).

Monitoring#

  • 현재 에러는 Datadog에서 noise로 작용할 수 있으므로, retry 성공 패턴을 필터링하는 것이 좋다.
  • 모니터링 쿼리 예시 (retry 실패만 감지):
text
service:cupixworks-any-bimrevision-agent status:error "Invalid OTG header" -"Successfully parsed"

Risk Assessment#

  • Risk level: low
  • 예상 복잡도: trivial
  • 사유: 에러가 자동으로 retry 성공하며, 실제 BIM 비교 작업에 영향을 주지 않는 noise 로그. stderr 로깅 레벨 조정만으로 해결 가능.