MaskWork#maskPanos stderr를 error로 잘못 분류 — 로깅 레벨 오류
RCA: MaskWork::maskPanos | RuntimeWarning: overflow encountered in exp
Error Log#
MaskWork::maskPanos | script /tmp/lib/face-body-detector/cupix_inference.py:266: RuntimeWarning: overflow encountered in exp
sigmoid_mask = 1.0 / (1.0 + np.exp(-logits_resized))
Impact#
- Service:
cupixworks-pano-postprocessor-instance - Team: bnbuilders
- 발생 횟수: 1 (클러스터 기준; 실제로는 동일 시간대에 20건 이상 반복 발생)
- 최초 발생: 2026-04-20T01:43:15.001Z
- 최근 발생: 2026-04-20T01:43:15.001Z
Root Cause Summary#
Python face-body-detector 스크립트의 sigmoid 연산에서 np.exp(-logits_resized) 호출 시 logits_resized 값이 매우 큰 음수일 때 -logits_resized가 매우 큰 양수가 되어 np.exp() 결과가 float64 범위를 초과하면서 RuntimeWarning: overflow encountered in exp가 발생한다. 이 경고는 Python의 warnings 모듈을 통해 stderr로 출력되며, Node.js 측 MaskWork::maskPanos 메서드가 subprocess의 stderr 출력을 모두 logger.error로 기록하기 때문에 Datadog에 error 레벨로 수집된다. 실제로는 NumPy가 overflow 시 inf를 반환하고 sigmoid 결과는 0.0으로 수렴하므로 마스킹 결과에 기능적 영향은 없으며, 프로세스는 exit code 0으로 정상 종료한다. 이 에러는 경고(warning)를 에러(error)로 잘못 분류한 로깅 문제이다.
Technical Analysis#
Code Path#
- Entry point:
pano-postprocessor-service.ts:126—maskWork.maskPanos()호출 MaskWork::maskPanos(mask-work.ts:23-59) — Python 스크립트를 child process로 실행BlurScriptPath=/tmp/lib/face-body-detector/run.sh(constants.ts:5)- Python 스크립트
cupix_inference.py:266— sigmoid 연산에서 overflow 발생 - stderr 핸들러 (
mask-work.ts:40-42) — 모든 stderr 출력을logger.error로 기록
MaskWork::maskPanos에서 Python subprocess를 생성하고 stderr를 처리하는 부분:
// mask-work.ts:29-42
const process: ChildProcessWithoutNullStreams = spawn('stdbuf', ['-oL', 'bash', BlurScriptPath], {
cwd: path.dirname(BlurScriptPath),
stdio: 'pipe',
env: { INPUT_DIRPATH: inputDir, OUTPUT_DIRPATH: outputDir, OPTION_FILE_PATH: optionPath }
});
process.stdout.on('data', (data) => {
logger.debug('MaskWork::maskPanos | script %s', data.toString());
});
process.stderr.on('data', (data) => {
logger.error('MaskWork::maskPanos | script %s', data.toString()); // 문제: stderr를 무조건 error로 분류
});
Python 측 문제 코드 (외부 의존성, 레포에 포함되지 않음):
# /tmp/lib/face-body-detector/cupix_inference.py:266
sigmoid_mask = 1.0 / (1.0 + np.exp(-logits_resized))
logits_resized에 큰 음수 값(-logits가 큰 양수)이 포함될 때 np.exp()가 float64 최대값(~1.8e308)을 초과하여 inf를 반환하고, Python RuntimeWarning이 stderr로 출력된다. 그러나 1.0 / (1.0 + inf) = 0.0이므로 sigmoid 결과값 자체는 수학적으로 올바르다 (해당 픽셀의 마스크 확률 ≈ 0).
프로세스 종료 처리:
// mask-work.ts:49-57
process.on('close', (code) => {
if (code === 0) {
logger.debug('MaskWork::maskPanos | success code:%d', code);
resolve(true);
} else {
logger.error('MaskWork::maskPanos | error code:%d', code);
reject(false);
}
});
프로세스는 exit code 0으로 정상 종료하므로 resolve(true)가 호출되고, 이후 change_masks, markMaskEnhancement 등 후속 단계가 정상 실행된다.
Log Evidence#
Datadog 쿼리 (overflow 에러):
service:cupixworks-pano-postprocessor-instance status:error "MaskWork::maskPanos"
동일 시간대에 overflow 외에도 UserWarning (PyTorch kernel caching)이 함께 stderr로 출력되어 error로 기록됨:
MaskWork::maskPanos | script /tmp/lib/face-body-detector/sam3/model/encoder.py:358: UserWarning: No PYTORCH_KERNEL_CACHE_PATH or HOME environment variable set! This disables kernel caching. (Triggered internally at /pytorch/aten/src/ATen/native/cuda/jit_utils.cpp:1426.)
spatial_shapes.prod(1).cumsum(0)[:-1],
프로세스가 정상 완료됨을 보여주는 로그:
Datadog 쿼리:
service:cupixworks-pano-postprocessor-instance "elapsed"
2026-04-20 10:58:45 KST | PanoPostprocessorService Elapsed Time - dd_step:blur_panos&dd_elapsed_time:383681ms
2026-04-20 10:58:51 KST | PanoPostprocessorService Elapsed Time - dd_step:change_masks&dd_elapsed_time:5876ms
blur_panos 단계가 정상 완료(383초)된 후 change_masks 단계도 성공적으로 실행됨. run | end 로그도 info 레벨로만 기록되고, error 레벨의 run | end 로그는 없음:
Datadog 쿼리:
service:cupixworks-pano-postprocessor-instance "PanoPostprocessorService::run | end" status:error
결과: 0건 — 에러로 종료된 run이 없음.
Fix Recommendation#
즉시 조치 (Critical)#
- 파일:
applications/agents/packages/cupix-pano-postprocessor/src/work/mask-work.ts:40-42 - stderr 출력을 무조건
logger.error로 기록하는 대신logger.warn으로 변경. Python의RuntimeWarning과UserWarning은 경고 수준이므로 error 레벨이 아닌 warn 레벨이 적절함. 이렇게 하면 Datadog error 알림에서 불필요한 노이즈가 제거됨.
단기 개선 (1주 이내)#
- Python 스크립트(
cupix_inference.py)에서np.exp호출 전에 입력값을 클리핑하거나scipy.special.expit(numerically stable sigmoid)를 사용하도록 변경. 예:np.clip(-logits_resized, -500, 500)적용 후np.exp호출. 이렇게 하면 warning 자체가 발생하지 않음. - PyTorch kernel caching warning 해결: Docker 컨테이너 환경에서
PYTORCH_KERNEL_CACHE_PATH환경변수를 설정하여UserWarning제거.
장기 개선 (재발 방지)#
- stderr 파싱 로직을 개선하여 Python warning(
RuntimeWarning,UserWarning)과 실제 에러를 구분. 예: stderr 출력에Warning:패턴이 포함되면logger.warn, 그 외는logger.error로 분류. - face-body-detector 의존성 업데이트 시 numerically stable sigmoid 구현이 포함되었는지 확인하는 CI 검증 추가.
Monitoring#
- 기존 Datadog 쿼리로 실제 에러만 모니터링:
service:cupixworks-pano-postprocessor-instance status:error "MaskWork::maskPanos | error code"
- stderr warning을 warn 레벨로 변경한 후 warning 빈도 추적:
service:cupixworks-pano-postprocessor-instance status:warn "RuntimeWarning"
Risk Assessment#
- Risk level: low
- 예상 복잡도: trivial
- 이 에러는 기능적 영향이 없는 Python RuntimeWarning이 Node.js stderr 핸들러에 의해 error로 잘못 분류된 것. 마스킹 프로세스는 정상 완료되며 결과물에 영향 없음. 수정은 로그 레벨 변경(1줄)으로 충분.