ChildProcessManager::setupEventHandlers | Child process stderr: Successfully parsed geometry resourc
RCA: ChildProcessManager stderr logging false positives
Overview#
What Happened#
2026-05-06 13:33~14:03 UTC 사이 cupixworks-any-bimrevision-agent 서비스에서 ChildProcessManager::setupEventHandlers | Child process stderr: 에러가 4건 발생했다. 실제로는 forge-agents 자식 프로세스의 geometry resource 파싱 성공 메시지("Successfully parsed geometry resource")가 stderr로 출력된 것을 부모 프로세스가 error 레벨로 잘못 분류한 false positive이다.
Quick Facts#
| Field | Value |
|---|---|
| exception.message | ChildProcessManager::setupEventHandlers | Child process stderr: Successfully parsed geometry resource for hash ..., attempt 2 |
| top_frame | child-process.manager.ts:140 |
| runtime | Node.js (forked child process via child_process.fork) |
| deploy | 04feb35fc (TSLA-12421, 2026-04-22) |
| env | production, us-west-2 |
Timeline#
- 2026-04-22 — TSLA-12421 배포:
BimCompareManager에{ stdioMode: 'pipe' }옵션 추가하여 forge child process의 stdout/stderr를 부모 프로세스에서 캡처하도록 변경 - 2026-05-06 13:33Z — 최초 false positive error 로그 발생
- 2026-05-06 14:03Z — 마지막 발생 (총 4건)
- 2026-05-06 — RCA 분석 완료
Error Log#
ChildProcessManager::setupEventHandlers | Child process stderr: Successfully parsed geometry resource for hash 뻬粕鰏딫겙䄛诣蕝퀢, attempt 2
Impact#
- Service:
cupixworks-any-bimrevision-agent - Team: wgyates
- 발생 횟수: 4
- 최초 발생: 2026-05-06T13:33:57.727Z
- 최근 발생: 2026-05-06T14:03:56.023Z
이 에러는 실제 장애를 나타내지 않는다. Geometry resource 파싱은 retry 후 성공했으며, 사용자 영향은 없다. 단, 같은 시간대 동일 서비스에서 31건의 error 레벨 로그가 발생했으며, 대부분 AWS SDK v2 deprecation 경고(14건), retry 정보 메시지(8건), 성공 메시지(4건) 등 false positive이다. 실제 에러는 geometry decode 실패(4건, 모두 retry 성공)와 bounding box 초과(1건)뿐이다.
Root Cause Summary#
TSLA-12421 커밋(04feb35fc, 2026-04-22)에서 BimCompareManager가 { stdioMode: 'pipe' } 옵션으로 ChildProcessManager를 생성하도록 변경되었다. 이로 인해 forge-agents 자식 프로세스의 stderr 출력이 부모 프로세스의 setupEventHandlers 핸들러(line 138-141)에 의해 캡처되며, 내용에 관계없이 모든 stderr 출력을 logger.error()로 기록한다. Unix/Node.js 관례상 stderr는 diagnostic output(경고, 진행 정보, 디버그)에도 사용되지만, 이 핸들러는 구분 없이 모두 error로 분류한다.
Technical Analysis#
Code Path#
- Entry point:
bim-revision-service.ts:69—BimCompareManager({ stdioMode: 'pipe' })생성 - Spawn:
child-process.manager.ts:70-76— fork 시 stderr를'pipe'로 설정 - Failure point:
child-process.manager.ts:138-141— stderr 데이터를 무조건logger.error()로 기록
배포된 코드 (TSLA-12421, 04feb35fc):
this._bimCompareManager = new BimCompareManager({ stdioMode: 'pipe' });
이전에는 옵션 없이 생성하여 inherit 모드(기본값)를 사용했으며, 자식 프로세스의 stderr가 부모에게 직접 전달되어 별도 로깅 없이 container stdout/stderr로 흘렀다.
const stdOut = this.options.stdioMode === 'pipe' ? 'pipe' : 'inherit';
const stdErr = this.options.stdioMode === 'pipe' ? 'pipe' : 'inherit';
try {
this.process = fork(actualScriptPath, {
stdio: ['inherit', stdOut, stdErr, 'ipc'],
});
pipe 모드에서 this.process.stderr가 non-null이 되어 아래 핸들러가 활성화된다:
this.process.stderr?.on('data', (data: Buffer) => {
const text = data.toString();
logger.error(`ChildProcessManager::setupEventHandlers | Child process stderr: ${text}`);
});
이 핸들러는 stderr 내용을 분석하지 않고 무조건 logger.error()로 기록한다. forge-agents 자식 프로세스는 retry 성공 메시지, AWS SDK 경고, 진행 정보를 stderr로 출력하므로 false positive가 발생한다.
기대 동작: stderr에서 실제 에러(AssertionError, ForgeAgentError)만 error 레벨로 기록하고, 정보성 메시지(성공, retry, deprecation 경고)는 warn 또는 info로 기록해야 한다.
실제 동작: 모든 stderr 출력이 error 레벨로 기록되어 모니터링 노이즈를 유발한다.
Log Evidence#
Datadog 검색 쿼리:
service:cupixworks-any-bimrevision-agent status:error @environment:production "ChildProcessManager::setupEventHandlers"
같은 시간대(12:30~14:30 UTC) 31건의 error 로그 중 실제 에러가 아닌 것들:
성공 메시지 (4건):
ChildProcessManager::setupEventHandlers | Child process stderr: Successfully parsed geometry resource for hash 뻬粕鰏딫겙䄛诣蕝퀢, attempt 2
AWS SDK v2 Deprecation 경고 (14건):
ChildProcessManager::setupEventHandlers | Child process stderr: (node:45) NOTE: The AWS SDK for JavaScript (v2) will enter maintenance mode on September 8, 2024 and reach end-of-support on September 8, 2025.
Retry 정보 메시지 (4건):
ChildProcessManager::setupEventHandlers | Child process stderr: Retrying to parse geometry resource for hash <unicode>, attempt 2 (waiting 10s)
실제 에러 (geometry decode 실패, 이후 retry 성공):
ChildProcessManager::setupEventHandlers | Child process stderr: AssertionError: Assertion failed - Invalid OTG header
at GeomDecoder.read (.../svf2-geometry-wss-loader.js:436:33)
관련 호스트: ip-10-1-41-244, ip-10-1-169-84, ip-10-1-175-8, ip-10-1-98-113, ip-10-1-98-203 (us-west-2, 5개 인스턴스에서 병렬 처리 중 발생).
Hypotheses Considered#
| # | Hypothesis | Evidence for | Evidence against | Verdict |
|---|---|---|---|---|
| H1 | stderr 핸들러가 모든 출력을 무조건 error로 분류하여 false positive 발생 | child-process.manager.ts:140에서 내용 필터링 없이 logger.error() 호출. 로그 메시지에 "Successfully parsed" 성공 텍스트가 error 레벨로 기록됨. TSLA-12421에서 stdioMode: 'pipe'로 변경하여 핸들러 활성화. |
— | Confirmed |
| H2 | forge-agents 자식 프로세스의 geometry 파싱 자체가 실패하여 데이터 손실 발생 | 초기 AssertionError: Invalid OTG header 에러 로그 존재 |
retry attempt 2에서 "Successfully parsed" 메시지 확인. 모든 4건의 geometry 파싱이 retry 후 성공. BimCompareManager::execute의 catch 블록 에러 로그 없음. |
Rejected |
| H3 | Node.js 프로세스 자체 오류 (OOM, crash 등) | — | 프로세스 정상 종료 확인. close/exit 이벤트 이후 정상 처리 로그 존재. error code 전파 없음. |
Rejected |
Fix Recommendation#
즉시 조치 (Critical)#
- 파일:
applications/agents/packages/base/src/manager/child-process.manager.ts:138-141 - stderr 핸들러에서 내용 기반 로그 레벨 분류 로직 추가. 패턴 매칭으로
Error,AssertionError,ForgeAgentError등 실제 에러 키워드가 포함된 경우만logger.error(), 나머지는logger.warn()또는logger.info()로 기록.
단기 개선 (1주 이내)#
- stderr 로그 레벨 분류를 위한 규칙을
ChildProcessOptions에 설정 가능하도록 개선. 예:stderrLogLevel: 'warn'옵션 추가로 기본 레벨을 조정하고, 실제 에러 패턴만 error로 승격. - forge-agents 라이브러리의 stderr 출력을 structured format(JSON)으로 변경하여 부모 프로세스에서 severity를 정확히 판단할 수 있도록 요청.
장기 개선 (재발 방지)#
- 자식 프로세스와 부모 프로세스 간 IPC 기반 structured logging 채널 도입. stderr 대신 IPC 메시지로 로그 전달하면 severity 정보 손실 없이 정확한 분류 가능.
ChildProcessManager의close/exit이벤트 핸들러도 exit code 0일 때 error가 아닌 info 레벨로 변경.
Monitoring#
- 수정 후 false positive 감소 확인:
service:cupixworks-any-bimrevision-agent status:error "ChildProcessManager::setupEventHandlers | Child process stderr" -"Error" -"AssertionError" -"ForgeAgentError"
- 위 쿼리 결과가 0이면 false positive 제거 확인.
Risk Assessment#
- Risk level: low
- 예상 복잡도: trivial