PreprocessorService::run | end - {"stack":"Error: PixGenie process failed with exit code 1. STDERR:
RCA: MobileSAMv2 IndexError in PixGenie Segment Extraction
Overview#
What Happened#
2026-04-20 09:35 UTC, cupixworks-pix-genie-preprocessor-instance 서비스에서 capture 45318(nswgov 테넌트)의 PixGenie 전처리 중 MobileSAMv2 모델이 165번째 이미지(전체 192장 중)에서 빈 logit tensor를 생성하여 torch.argmax()에서 IndexError가 발생했다. 이로 인해 Python 프로세스가 exit code 1로 종료되었고, Node.js agent가 capture의 pix_genie_state를 Error로 영구 설정했다.
Quick Facts#
| Field | Value |
|---|---|
| exception.class | IndexError |
| exception.message | argmax(): Expected reduction dim 0 to have non-zero size. |
| top_frame | mobilesamv2.py:200 |
| runtime | Python 3.10, PyTorch (CUDA), pixgenie 0.1.28 |
| env | production, ap-southeast-2 |
Affected Teams#
| Team / Domain | Error Count | Impact |
|---|---|---|
| sinsw / nswgov | 1 | capture 45318 ("3D Map [08:45 AM]") 전처리 실패, pix_genie_state가 Error로 영구 설정됨 |
Timeline#
- 09:30:10Z -- PreprocessorService 초기화, capture 45318 로드 (reconstruction_state: done)
- 09:30:10Z -- PixGenie Python 프로세스 시작 (job 106792)
- 09:32:51Z -- MobileSAMv2 모델 로드 완료, segment extraction 시작 (192장)
- 09:35:09Z -- 164/192 (85%) 완료 후 165번째 이미지에서
IndexError발생 - 09:35:11Z -- Python 프로세스 exit code 1, Node.js agent가
pix_genie_state를 Error로 설정 - 09:35:11Z -- workspace 정리 및 서비스 종료
Error Log#
PreprocessorService::run | end - {"stack":"Error: PixGenie process failed with exit code 1. STDERR: ...
Traceback (most recent call last):
File "/tmp/lib/pixgenie/pixgenie/scripts/docker_entrypoint.py", line 123, in <module>
main()
File "/tmp/lib/pixgenie/pixgenie/scripts/docker_entrypoint.py", line 101, in main
run_pipeline(
File "/tmp/lib/pixgenie/pixgenie/scripts/run.py", line 84, in run_pipeline
extract_segments(
File "/tmp/lib/pixgenie/pixgenie/scripts/extract_segments.py", line 136, in extract_segments
masks, mask_scores = model.get_segments(image)
File "/tmp/lib/pixgenie/pixgenie/sam_models/mobilesamv2.py", line 221, in get_segments
return self._get_segments(image)
File "/tmp/lib/pixgenie/pixgenie/sam_models/mobilesamv2.py", line 200, in _get_segments
masks = torch.argmax(logit, dim=0)
IndexError: argmax(): Expected reduction dim 0 to have non-zero size.
Impact#
- Service:
cupixworks-pix-genie-preprocessor-instance - Team: sinsw
- 발생 횟수: 1
- 최초 발생: 2026-04-20T09:35:11.385Z
- 최근 발생: 2026-04-20T09:35:11.385Z
capture 45318의 PixGenie 전처리가 완전히 실패했다. pix_genie_state가 Error로 설정되어 자동 복구가 불가능하며, 수동으로 상태를 리셋하고 재처리해야 한다. 다른 동시 실행 중인 job(106796, 106797)은 영향 없이 정상 처리되었다. 지난 24시간 동안 이 IndexError는 이 건 외에 발생하지 않았다.
Root Cause Summary#
MobileSAMv2 모델의 _get_segments() 메서드(mobilesamv2.py:200)에서 특정 이미지에 대해 segment를 감지하지 못해 빈(empty) logit tensor가 생성되었고, 이 빈 tensor에 대해 torch.argmax(logit, dim=0)을 호출하면서 IndexError가 발생했다. 192장의 equirectangular 이미지 중 165번째 이미지가 문제였으며, 해당 이미지가 featureless한 표면이거나 극단적인 노출/손상된 프레임일 가능성이 높다. Python pixgenie 라이브러리(v0.1.28)에 빈 logit에 대한 방어 로직이 없으며, Node.js agent에도 프레임 단위 에러 핸들링이나 retry 로직이 없어 단일 프레임 실패가 전체 capture 실패로 이어졌다.
Technical Analysis#
Code Path#
1. Node.js Agent -- 프로세스 시작
Entry point: preprocessor-service.ts:93 -- executePixGenieProcessing() 호출
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');
executePixGenieProcessing()이 throw하면 catch 블록으로 진입하여 PixGenieState.Error로 영구 설정된다.
catch (error) {
await this.pixGenieManager.updatePixGenieState(captureId!, TESLA.PixGenieState.Error);
logger.error('PreprocessorService::run | end - %s', stringifyError(error));
}
2. PixGenieManager -- 프로세스 실행 및 정리
async executePixGenieProcessing(cpCapture: CPCapture): Promise<void> {
const workspaceDir = `${Constants.DefaultWorkspaceDir}/capture_${cpCapture.id}`;
const outputDir = `${workspaceDir}/output`;
try {
this._fileSystemManager.createOutputDir(outputDir);
const processParams: PixGenieProcessParams = { /* ... */ };
await this._pixGenieProcess.execute(processParams);
await this.uploadPixGenieResult(cpCapture.id, outputDir);
} finally {
await this._fileSystemManager.cleanupWorkspace(workspaceDir);
}
}
execute()가 실패하면 uploadPixGenieResult()은 호출되지 않고, finally에서 workspace가 삭제되어 디버깅용 데이터도 사라진다.
3. PixGenieProcess -- Python 프로세스 에러 핸들링
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}` : ''}`));
}
});
Non-zero exit code는 즉시 reject되며, retry 로직이 전혀 없다.
4. Python -- Failure Point
masks = torch.argmax(logit, dim=0)
logit tensor의 dim=0 크기가 0일 때(segment가 하나도 감지되지 않은 경우) torch.argmax()가 IndexError를 발생시킨다. 이 함수 호출 전에 logit tensor의 크기를 검증하는 guard가 없다.
기대 동작: MobileSAMv2가 이미지에서 segment를 감지하고 non-empty logit tensor를 반환 -> argmax로 최적 mask 선택
실제 동작: 165번째 이미지에서 segment가 하나도 감지되지 않아 empty logit tensor 반환 -> argmax 호출 시 IndexError crash
Log Evidence#
Datadog에서 사용한 쿼리:
service:cupixworks-pix-genie-preprocessor-instance status:error @environment:production
service:cupixworks-pix-genie-preprocessor-instance 45318
capture 45318의 전체 처리 로그 (핵심 발췌):
09:30:10.815Z | loaded capture - id: 45318, name: 3D Map [08:45 AM], reconstruction_state: done, current_step: 3d_map_creation_completed
09:32:06.837Z | Video file: R0010219.MP4, videoFrameCount: 613
09:32:44.651Z | ExtractSegmentsConfig loaded -- processing capture_alignments_derotated.json, output to pixgenie.sqlite
09:32:51.046Z | Extracting Segments: 0% | 0/192
09:35:09.956Z | Extracting Segments: 85% | 164/192 [02:18<00:23, 1.18it/s]
09:35:09.956Z | Traceback... IndexError: argmax(): Expected reduction dim 0 to have non-zero size. at mobilesamv2.py:200
09:35:11.046Z | PixGenieProcess::execute | failed - {}
09:35:11.081Z | FileSystemManager::cleanupWorkspace | workspace cleaned: /tmp/workspace/capture_45318
09:35:11.385Z | PreprocessorService::run | end - {full error stack}
Processing 상세 정보:
{
"capture_id": 45318,
"job_id": 106792,
"user": "danielle.shield4@det.nsw.edu.au",
"video": "R0010219.MP4",
"video_frames": 613,
"total_segments": 192,
"failed_at_segment": 165,
"processing_duration_sec": 301,
"host": "74ae52ead55b",
"pixgenie_version": "0.0.13225_db62c1c51ff4b1dedd524b964d9457b4813488a9_20260114"
}
24시간 빈도 분석 (Datadog):
service:cupixworks-pix-genie-preprocessor-instance status:error @environment:production
- IndexError (argmax): 1건 (capture 45318만 해당)
- MaskWork PyTorch kernel cache warning: ~98건 (별도 fingerprint, benign warning)
- 동시 실행 중인 다른 job(106796, 106797)은 정상 완료
Hypotheses Considered#
| # | Hypothesis | Evidence for | Evidence against | Verdict |
|---|---|---|---|---|
| H1 | MobileSAMv2 모델이 특정 이미지에서 segment를 감지하지 못해 empty logit tensor 생성 | traceback에서 torch.argmax(logit, dim=0) 호출 시 dim 0 크기가 0이라는 에러 메시지. 192장 중 164장까지 정상 처리 후 165번째에서만 실패. 다른 동시 job은 정상 완료. |
-- | Confirmed |
| H2 | GPU 메모리 부족(OOM)으로 인한 텐서 할당 실패 | GPU 집약적 작업이며 동시에 여러 job 실행 중 | OOM 에러 시 PyTorch는 RuntimeError: CUDA out of memory를 발생시키지 IndexError를 발생시키지 않음. 에러 메시지가 명확히 "non-zero size" 문제를 지적. |
Rejected |
| H3 | 손상된 비디오 프레임(R0010219.MP4의 특정 프레임)으로 인한 모델 입력 이상 | 360도 카메라 영상(equirectangular projection)이며, 특정 프레임이 극단적인 노출이나 featureless surface일 수 있음. 613 프레임에서 192장의 equi 이미지 추출. | 직접적 이미지 검증 불가 -- workspace가 삭제됨. 단, empty logit이 발생하는 원인으로 가능성 있음. | Inconclusive |
| H4 | pixgenie 라이브러리 버전 문제 또는 regression | pixgenie_version 0.0.13225 (2026-01-14 빌드) | 지난 24시간 다른 capture에서 동일 에러 없음. 라이브러리 자체보다는 특정 이미지 입력에 의존하는 문제. | Rejected |
Fix Recommendation#
즉시 조치 (Critical)#
- capture 45318 수동 복구: TESLA API를 통해
pix_genie_state를 리셋하고 재처리 트리거. 동일 이미지에서 다시 실패할 수 있으므로, Python 측 수정 전에는 재처리가 근본 해결이 아님.
단기 개선 (1주 이내)#
-
Python pixgenie -- empty logit guard 추가 (
mobilesamv2.py:200부근):torch.argmax(logit, dim=0)호출 전에 logit tensor의 dim=0 크기가 0인지 검사- empty인 경우 해당 이미지를 skip하고 빈 mask/score를 반환하거나 warning 로그 출력 후 다음 이미지로 진행
- pixgenie 라이브러리는 별도 repository에서 관리되므로 해당 팀과 협의 필요
-
Python pixgenie -- frame-level error handling (
extract_segments.py:136부근):model.get_segments(image)호출을 try-except로 감싸서 개별 프레임 실패가 전체 pipeline을 중단하지 않도록 처리- 실패한 프레임은 skip하고 로그 기록
장기 개선 (재발 방지)#
-
Node.js agent -- retry 로직 추가:
pixgenie.process.ts에서 Python 프로세스 실패 시 제한된 횟수(1-2회) retry 구현. 다만 동일 입력이면 동일 에러가 반복되므로 Python 측 수정이 우선. -
실패 시 workspace 보존 옵션:
pix-genie-manager.ts의 finally 블록에서 에러 시 workspace를 즉시 삭제하지 않고, 일정 시간 또는 설정에 따라 디버깅용으로 보존하는 옵션 추가. -
Partial result 업로드: 192장 중 164장은 정상 처리되었으므로, partial result를 활용할 수 있는 로직 검토. 전체 실패보다는 부분 성공이 사용자에게 더 나은 경험 제공.
Monitoring#
추가 권장 메트릭/알림:
service:cupixworks-pix-genie-preprocessor-instance status:error "argmax" @environment:production
service:cupixworks-pix-genie-preprocessor-instance "PixGenieProcess::execute | failed" @environment:production
- PixGenie 프로세스 실패율 모니터 추가: 일정 기간 내 실패 건수가 임계값 초과 시 알림
- Segment extraction 성공률 메트릭: 전체 이미지 수 대비 성공적으로 처리된 이미지 비율 추적
Risk Assessment#
- Risk level: low (단일 발생, 특정 이미지 입력에 의존하는 edge case)
- 예상 복잡도: standard (Python pixgenie에 guard 추가는 간단하나, 별도 repository/빌드 파이프라인 경유 필요)