PixGenie process failed with exit code 11. STDERR: clusters: 100%|██████████| 1/1 [00:00<?, ?it/s]
RCA: PixGenie process failed with exit code 11 (SIGSEGV during native library teardown)
Overview#
What Happened#
cupix-pix-genie-preprocessor-agent가 capture_47326 (tenant nswgov, region ap-southeast-2)의 PixGenie 전처리를 실행하던 중, Python 프로세스가 모든 처리를 끝낸 직후 native library teardown 단계에서 SIGSEGV(11)로 크래시했다. 프로세스가 non-zero로 종료되자 agent가 이를 PixGenie process failed with exit code 11 에러로 보고하고 capture 상태를 Error로 마킹했다. 처리 결과물은 이미 생성되었으나 업로드 단계에 도달하지 못했다.
Quick Facts#
| Field | Value |
|---|---|
| exception.class | Error (Node.js generic Error) |
| exception.message | PixGenie process failed with exit code 11. STDERR: ... Received fatal signal: SIGSEGV(11) |
| top_frame | src/process/pixgenie.process.ts:111 |
| crash frame (native) | cupix::foundation::factory::detail::unregisterObjectCreator(std::type_info const&) in libfoundation.so |
| runtime | Node.js agent + Python 3.12 child process (PixGenie native libs, g3log) |
| env | production, ap-southeast-2, tenant nswgov |
Affected Teams#
| Team / Domain | Error Count | Impact |
|---|---|---|
sinsw / nswgov |
1 (capture 47326) | PixGenie 전처리 결과 업로드 실패, capture pix_genie_state = Error |
Timeline#
- 2026-08-07 11:35 KST — PixGenie Python 프로세스 시작, video decoding 및 feature 추출 진행.
- 2026-08-07 11:47 KST —
Extracting Features: 100%|██████████| 226/226완료 (모든 처리 종료). - 2026-08-07 11:49:23 KST —
Pipeline result saved to: /tmp/workspace/capture_47326/output/pixgenie_result.json(파이프라인 결과 저장 성공). - 2026-08-07 11:49:24 KST — native library teardown 중
SIGSEGV(11)발생, 프로세스 non-zero 종료. - 2026-08-07 11:49:24 KST — agent가
PixGenie process failed with exit code 11에러 로깅, capturepix_genie_state = Error, workspace cleanup.
Error Log#
PixGenie process failed with exit code 11. STDERR: ... Extracting Features: 100%|██████████| 226/226 [08:31<00:00, 2.26s/it]******* FATAL SIGNAL *******
file: , function: , Received fatal signal: SIGSEGV(11) PID: 33
***** SIGNAL SIGSEGV(11)
******* STACKDUMP *******
stack dump [1] /tmp/lib/pixgenie/pixgenie/lib/pixgenieutil-x64-ubuntu22.04-gcc-release/libg3log.so+0x15d5b [0x7fa4912dcd5b]
stack dump [2] /usr/lib/x86_64-linux-gnu/libc.so.6+0x45330 [0x7fa57b4fb330]
stack dump [3] /tmp/lib/pixgenie/pixgenie/lib/pixgenieutil-x64-ubuntu22.04-gcc-release/libfoundation.so : cupix::foundation::factory::detail::unregisterObjectCreator(std::type_info const&)+0xa1 [0x7fa45a6a5b51]
stack dump [4] /tmp/lib/pixgenie/pixgenie/lib/pixgenieutil-x64-ubuntu22.04-gcc-release/libscenemodel.so : cupix::scene_model::unload()+0x14 [0x7fa45aff8254]
stack dump [5] /tmp/lib/pixgenie/pixgenie/lib/pixgenieutil-x64-ubuntu22.04-gcc-release/libfoundation.so : cupix::foundation::bootstrap::unload()+0x4d [0x7fa45a6d107d]
stack dump [6] /lib64/ld-linux-x86-64.so.2+0x10f2 [0x7fa57b8030f2]
stack dump [7] /lib64/ld-linux-x86-64.so.2+0x5578 [0x7fa57b807578]
stack dump [8] /usr/lib/x86_64-linux-gnu/libc.so.6+0x47a76 [0x7fa57b4fda76]
stack dump [9] /usr/lib/x86_64-linux-gnu/libc.so.6+0x47bbe [0x7fa57b4fdbbe]
stack dump [10] /usr/lib/x86_64-linux-gnu/libc.so.6+0x2a1d1 [0x7fa57b4e01d1]
stack dump [11] /usr/lib/x86_64-linux-gnu/libc.so.6__libc_start_main+0x8b [0x7fa57b4e028b]
stack dump [12] /usr/bin/python3_start+0x25 [0x657bc5]
Impact#
- Service:
cupixworks-pix-genie-preprocessor-instance - Team: sinsw (tenant
nswgov) - 발생 횟수: 1 (cluster 기준). 14일 창 내 SIGSEGV-during-unload 시그니처 동일 발생 2건, 유사 SIGSEGV 1건 추가.
- 최초 발생: 2026-08-07 11:49 KST
- 최근 발생: 2026-08-07 11:49 KST
동일 서비스에서 14일 창 upload completed 성공 로그가 50건 이상 (조회 limit 도달)이고 error-level PreprocessorService::run | end 실패가 9건이므로, 성공이 지배적인 가운데 발생하는 저빈도 간헐 실패다. capture 처리 자체는 완료되었으나 결과 업로드가 누락되어 재실행이 필요하다.
Root Cause Summary#
PixGenie Python 프로세스가 모든 처리 (feature 추출 226/226, pixgenie_result.json 저장)를 정상 완료한 뒤, native C++ 라이브러리 teardown (cupix::foundation::bootstrap::unload → cupix::scene_model::unload → cupix::foundation::factory::detail::unregisterObjectCreator) 중 SIGSEGV(11)로 크래시했다. 이 크래시는 g3log signal handler가 stack dump를 남기고 프로세스를 non-zero exit code로 종료시킨다. pixgenie.process.ts의 setupProcessHandlers는 code !== 0이면 무조건 PixGenie process failed with exit code ${code} 에러로 reject하므로, 처리 산출물이 이미 존재하더라도 프로세스가 처리 완료 후 teardown 단계에서만 죽었는지 구분하지 못하고 전체 job을 실패로 처리한다. 근본 원인은 PixGenie native library의 shutdown-time segfault (C++ static/전역 객체 소멸 순서 문제로 추정)이며, agent 측 결함은 teardown 크래시와 진짜 처리 실패를 구분하지 못하는 exit-code 처리 방식이다.
Technical Analysis#
Code Path#
- Entry point:
src/preprocessor-service.ts:66(PreprocessorService.run) - 처리 실행:
src/manager/pix-genie-manager.ts:56(executePixGenieProcessing) - Python 프로세스 실행:
src/process/pixgenie.process.ts:52(runPythonProcess) - Failure point:
src/process/pixgenie.process.ts:105-113(close핸들러의 non-zero exit 처리)
run은 처리 성공 시에만 pix_genie_state = Done으로, catch 블록에서 Error로 마킹한다.
logger.info('PreprocessorService::run | Starting Pix Genie preprocessing');
const start = Date.now();
await this.pixGenieManager.executePixGenieProcessing(cpCapture);
logDuration(start, Date.now(), `executePixGenieProcessing - capture_id: ${cpCapture.id}`, 'PreprocessorService');
logger.info('PreprocessorService::run | Pix Genie preprocessing completed');
await this.pixGenieManager.updatePixGenieState(captureId, TESLA.PixGenieState.Done);
logger.info('PreprocessorService::run | successfully completed');
}
} catch (error) {
await this.pixGenieManager.updatePixGenieState(captureId!, TESLA.PixGenieState.Error);
logger.error('PreprocessorService::run | end - %s', stringifyError(error));
executePixGenieProcessing은 execute (내부에서 verifyOutput) 성공 뒤에 uploadPixGenieResult를 호출한다. 즉 execute가 reject하면 업로드는 실행되지 않는다.
const processStart = Date.now();
await this._pixGenieProcess.execute(processParams);
logDuration(processStart, Date.now(), `pixgenie_python_process - capture_id: ${cpCapture.id}`, 'PixGenieManager');
await this.uploadPixGenieResult(cpCapture.id, outputDir);
실제 실패는 runPythonProcess의 close 핸들러에서 발생한다. exit code가 0이 아니면 STDERR 전체를 붙여 Error로 reject한다. teardown SIGSEGV로 인한 종료도 이 경로로 들어온다.
this._process.on('close', (code) => {
logger.debug('PixGenieProcess | process exited with code: %d', code);
if (code === 0) {
resolve();
} else {
reject(new Error(`PixGenie process failed with exit code ${code}${stderr ? `. STDERR: ${stderr}` : ''}`));
}
});
기대 동작: Python 프로세스가 처리를 완료하고 산출물 (pixgenie.sqlite)을 남기면 agent가 이를 업로드하고 capture를 Done으로 마킹.
실제 동작: 처리는 완료되었으나 native teardown 중 SIGSEGV로 프로세스가 non-zero 종료 → close 핸들러가 무조건 실패 reject → verifyOutput/uploadPixGenieResult 미실행 → capture Error 마킹.
native stack은 shutdown 전용 경로임을 보여준다. bootstrap::unload (frame 5) → scene_model::unload (frame 4) → unregisterObjectCreator (frame 3), 그리고 frame 6-7의 ld-linux 및 frame 8-9의 libc __run_exit_handlers 계열은 프로세스 종료 시 static destructor/atexit 실행 중임을 나타낸다. 즉 세그폴트는 처리 로직이 아니라 라이브러리 언로드 순서에서 발생했다.
Log Evidence#
사용한 Datadog 쿼리:
service:cupixworks-pix-genie-preprocessor-instance "PixGenie process failed with exit code"
14일 창 4건 조회. capture별 전체 흐름 확인 쿼리:
service:cupixworks-pix-genie-preprocessor-instance "capture_47326"
파이프라인이 크래시 직전 정상 완료되었음을 보여주는 로그:
2026-08-07 11:49:23 info PixGenieProcess | [2026-08-07T02:49:23.067Z] Pipeline result saved to: /tmp/workspace/capture_47326/output/pixgenie_result.json
메모리/디스크가 충분해 OOM이 아님을 보여주는 processing monitor 로그:
cpuUsage(%): 93.62, freeMemory(MB): 23389.07, VmSize(MB): 15339.18, vmRSS(MB): 6318.13, VmPeak(MB): 15386.64, freeDisk: 482357.93, timestamp: 2026-08-07T02:36:15
avg.cpuUsage(%d): 55.66, min.freeMemory(MB): 23389.07, max.VmPeak(MB): 15386.64
capture_47326에는 uploadPixGenieResult 로그가 전혀 없어 업로드 단계에 도달하지 못했음을 확증한다. 대조로, 정상 처리된 capture들은 다음과 같이 업로드 성공 로그를 남긴다:
2026-08-06 11:59:26 info PixGenieManager::uploadPixGenieResult | uploading result for capture: 749615
2026-08-06 11:59:26 info PixGenieManager::uploadPixGenieResult | file verified - size: 218620 KB
2026-08-06 11:59:32 info PixGenieManager::uploadPixGenieResult | upload completed
크래시 후 정리 흐름 로그:
2026-08-07 11:49:24 error PreprocessorService::run | end - {"stack":"Error: PixGenie process failed with exit code 11. STDERR: ...
2026-08-07 11:49:24 info FileSystemManager::cleanupWorkspace | workspace cleaned: /tmp/workspace/capture_47326
2026-08-07 11:49:24 info PreprocessorService::run | end
2026-08-07 11:49:24 info PreprocessorService::terminateService | force shutdown after 600 seconds
동일 시그니처의 크래시가 이전에도 발생했음 (SIGSEGV + unregisterObjectCreator unload frame + feature 100% 완료). 14일 창 발생: 2026-07-30 05:31, 2026-07-30 18:07, 2026-08-07 11:49 (2건, 동일 이벤트가 pixgenie.process.ts:37과 preprocessor-service.ts:102에서 각각 로깅됨).
Hypotheses Considered#
| # | Hypothesis | Evidence for | Evidence against | Verdict |
|---|---|---|---|---|
| H1 | PixGenie native library가 처리 완료 후 teardown (bootstrap::unload → scene_model::unload → unregisterObjectCreator)에서 SIGSEGV로 크래시, agent가 non-zero exit을 무조건 실패로 처리 |
native stack dump frame 3-5가 unload 경로, frame 8-9가 libc exit handler; Pipeline result saved to ... pixgenie_result.json가 크래시 직전 (02:49:23) 기록; Extracting Features: 100% 완료; pixgenie.process.ts:105-113가 code !== 0이면 무조건 reject |
— | Confirmed |
| H2 | 메모리 부족 (OOM)으로 인한 크래시 | 대용량 ML 모델 (dinov3 1.13G) 로딩 | processing monitor 로그상 freeMemory 23 GB 이상, freeDisk 482 GB, VmPeak 15 GB로 여유 충분; SIGSEGV는 OOM-killer의 SIGKILL(9)과 다름 | Rejected |
| H3 | 실제 처리 실패 (feature 추출 또는 pipeline 로직 오류) | exit code non-zero | feature 추출 226/226 완료, pipeline result 저장 성공 로그 존재; 크래시 위치가 처리 로직이 아닌 unload 경로 | Rejected |
| H4 | agent의 2시간 timeout (TIMEOUT_MS)으로 인한 abort |
runPythonProcess에 timeout 로직 존재 (pixgenie.process.ts:56-61) |
처리 전체 소요가 약 14분 (11:35~11:49)으로 2시간 미만; process timeout, aborting warn 로그 없음; 종료 원인은 SIGSEGV |
Rejected |
| H5 | exit code 11이 signal 11(SIGSEGV)을 그대로 반영한 값이며, g3log handler가 아니라 kernel이 프로세스를 죽였다 | STDERR에 SIGSEGV(11) 명시 |
STDERR에 g3log FATAL SIGNAL + STACKDUMP 블록이 존재 = g3log signal handler가 신호를 잡아 dump 후 종료. Node close의 code가 11로 채워진 것은 handler가 코드 11로 exit했음을 시사 (kernel-kill이면 code=null, signal='SIGSEGV') |
Inconclusive |
Fix Recommendation#
즉시 조치 (Critical)#
- 재실행으로 capture 47326을 복구한다. 처리 로직 자체는 정상이므로 재시도 시 teardown 크래시가 재현되지 않으면 성공 가능성이 높다.
- native teardown 크래시는 데이터 손상이 아니라 shutdown-only 이슈다. 즉시 코드 변경 없이 재처리로 대응 가능.
단기 개선 (1주 이내)#
src/process/pixgenie.process.ts의close핸들러 (105-113)와execute(32-40)에서, non-zero exit이더라도 산출물 검증을 우선하도록 로직 방향을 조정한다. 구체적으로verifyOutput(pixgenie.process.ts:121-127)이pixgenie.sqlite존재 및 유효성을 확인하면, STDERR에Received fatal signal같은 teardown-only 크래시 시그니처가 있고 산출물이 완전한 경우 성공으로 처리하는 방향을 검토한다. 단, 산출물 무결성 (sqlite 완전 flush 여부)을 반드시 검증해야 하며, 검증 실패 시에는 기존대로 실패 처리한다.pixgenie_result.json저장 로그 이후pixgenie.sqlite가 완전히 기록되는 시점을 로그로 남겨, 크래시 시 산출물이 완전한지 판정할 근거를 확보한다.
장기 개선 (재발 방지)#
- PixGenie native library (
libfoundation.so,libscenemodel.so)의 shutdown-time segfault를 근본 수정한다.unregisterObjectCreator에서의 크래시는 C++ static/전역 factory 객체의 소멸 순서 (static destruction order fiasco) 또는 이미 언로드된 모듈의 심볼 참조가 원인일 가능성이 높으므로, PixGenie 라이브러리 소유 팀에서 factory teardown 순서를 점검한다. - 처리 완료 후 exit을 명시적으로 성공 코드로 종료하도록
docker_entrypoint.py레벨에서 파이프라인 완료 직후 즉시 성공 종료 (예:os._exit(0))를 검토해, 정상 완료된 작업이 teardown 크래시로 실패 처리되지 않도록 한다. 단 이는 리소스 정리 우회이므로 native 팀과 협의가 필요하다.
Monitoring#
teardown SIGSEGV 재발 추적 (배포 후 감소 확인용):
service:cupixworks-pix-genie-preprocessor-instance status:error "PixGenie process failed with exit code 11"
전처리 실패 전반 추이:
service:cupixworks-pix-genie-preprocessor-instance status:error "PreprocessorService::run | end"
정상 업로드 완료 건수 (성공률 확인용, 위 실패 쿼리와 비교):
service:cupixworks-pix-genie-preprocessor-instance "PixGenieManager::uploadPixGenieResult | upload completed"
Risk Assessment#
- Risk level: low
- 예상 복잡도: standard
capture 처리 결과가 손상되지 않고 재실행으로 복구 가능하므로 즉시 위험도는 낮다. 다만 native teardown 크래시가 간헐적으로 정상 완료 작업을 실패로 처리하므로, agent의 exit-code 판정 로직 개선과 native library 근본 수정이 병행되어야 재발을 막을 수 있다. agent 측 단기 개선은 산출물 무결성 검증을 전제로 해야 하므로 standard 복잡도로 평가한다.