Process killed by signal SIGSEGV (code: null)
RCA: Process killed by signal SIGSEGV (code: null)
Overview#
What Happened#
2026-07-14 12:05 KST 무렵 cupixworks-capture-refinement-arm-instance 서비스 (us-west-2, tenant cupix, team clark-vdc)에서 두 개의 refinement job (job.id 1194561, 1194562, captures 734596/734597) 이 native scene-mapper 자식 프로세스에서 SIGSEGV 로 종료됨. 두 job 모두 동일 세션(4fdf37af58d3ef3843f0281770c366eb580eb1d5) 하에서 실행되었으며, crash 직전 video filepath not found - 693547.insv 경고가 수십 번 반복되고 Empty bim drawing detected. Skip creating grid map. 경고가 관측됨.
Quick Facts#
| Field | Value |
|---|---|
| exception.class | Error |
| exception.message | Process killed by signal SIGSEGV (code: null) |
| top_frame | /tmp/agent/dist/app.cjs:5248 (bundled from packages/base/src/manager/child-process.manager.ts:114) |
| runtime | Node.js child process (fork) loading native .node addon via require(libPath) |
| env | production, region us-west-2, arm64 instance |
Affected Teams#
| Team / Domain | Error Count | Impact |
|---|---|---|
| clark-vdc (tenant cupix) | 2 (jobs 1194561, 1194562) | Capture refinement pipeline for captures 734596/734597 failed; downstream reconstruction/preview blocked until re-run or manual intervention. |
지난 14일 동안 동일 stack (ScenemapperManager::execute | Process killed by signal SIGSEGV) 이 15회 관측됨 (아래 Log Evidence 참조). 동일한 native 경로에서 반복되는 재현 가능한 이슈.
Timeline#
- 2026-07-14 12:05:28 KST — job 1194561 시작 (
RefinementService::init,authenticate,run | begin). - 2026-07-14 12:05:32 KST — 수십 건의
video filepath not found - 693547.insv경고,Empty bim drawing detected. Skip creating grid map.경고. - 2026-07-14 12:05:50 KST — job 1194561 자식 프로세스 SIGSEGV 로 종료 (
ChildProcessManager::setupEventHandlers | Child process closed/exited, capture 734597, hostb3a90aff006d). - 2026-07-14 12:05:57 KST — job 1194562 도 동일 원인으로 SIGSEGV (capture 734596, host
812624bde753). - 2026-07-14 12:05:51 KST —
RefinementService::terminateService | force shutdown after 10 seconds로그 이후 프로세스 종료.
Error Log#
Process killed by signal SIGSEGV (code: null)
Impact#
- Service:
cupixworks-capture-refinement-arm-instance - Team: clark-vdc
- 발생 횟수 (이 클러스터): 2
- 최초 발생: 2026-07-14 12:05 KST
- 최근 발생: 2026-07-14 12:05 KST
- 14일 누적 (동일 stack): 15회 (2026-07-01 ~ 2026-07-14)
Root Cause Summary#
Refinement pipeline 은 ScenemapperManager 가 fork() 로 띄운 자식 프로세스에서 native scene-mapper library (ScenemapperApi, require(libPath) 로 dynamic load) 의 Refiner.process() 를 호출한다. 이 native C++ 코드가 SIGSEGV 로 크래시하여 부모 프로세스에 close(null, 'SIGSEGV') 이벤트가 발생하고, ChildProcessManager 가 Process killed by signal SIGSEGV (code: null) Error 로 pending IPC 를 reject한다. Crash 직전 로그에서 video filepath not found - 693547.insv 가 반복되고 Empty bim drawing detected. Skip creating grid map. 이 나타나는 것으로 보아, refiner 에 전달되는 입력 (video 파일 및/또는 BIM drawing) 이 예상 상태와 불일치하는 상황에서 native 쪽 nil/dangling pointer dereference 가 트리거되는 것으로 보인다. TypeScript 레이어에서는 방어할 수 없는 native crash 이며, 자식 프로세스 재시작 / 재시도 로직도 없어 job 이 그대로 실패한다.
Technical Analysis#
Code Path#
- Entry point:
packages/cupix-capture-refinement-agent/src/refinement-service.ts:305(runRefinement) - Native call site:
packages/cupix-capture-refinement-agent/src/process/scenemapper.process.ts:43-47(require(libPath)로 native addon 로드 후Refiner.process()실행) - Crash 감지:
packages/base/src/manager/child-process.manager.ts:107-120(close이벤트에서 signal 을 기반으로 Error 생성) - Failure point: 자식 프로세스 안 native
.nodeaddon 내부 (Datadog 로그에는 native stack 이 노출되지 않음)
runRefinement 은 refiner 를 실행하기 전에 log watcher 를 열고 execute 호출로 IPC 를 통해 native 쪽에서 Refiner.process() 를 트리거한다:
private runRefinement = async (cpCapture: CPCapture): Promise<void> => {
logger.debug('RefinementService::runRefinement | begin');
this.scenemapperLogManager.watchLogFile(Constants.DefaultWorkspacePath);
await this.scenemapperManager.checkChildProcess();
await this.scenemapperManager.execute({
refinerParamsFilepath: cpCapture.refinementParamsJsonFilePath
});
if (this.scenemapperLogManager.logWatcher) {
logger.debug('RefinementService::runRefinement | close log watcher');
this.scenemapperLogManager.logWatcher.close();
}
logger.debug('RefinementService::runRefinement | end');
};
ScenemapperManager::execute 는 IPC 로 자식에게 execute message 를 보내고, 자식은 native addon 을 로드해 Refiner.process() 를 실행한다:
private execute = (params: ExecuteMessage): void => {
this.log(`ScenemapperProcess::execute | params: ${JSON.stringify(params)}`);
if (!this.libPath || !params?.refinerParamsFilepath) {
throw new Error('ScenemapperProcess::execute | Required parameters missing');
}
// eslint-disable-next-line @typescript-eslint/no-require-imports
const ScenemapperApi = require(this.libPath);
const Refiner = new ScenemapperApi.refiner();
Refiner.load_params(params.refinerParamsFilepath);
Refiner.process();
};
이 시점 native 코드가 SIGSEGV 로 죽으면 부모의 ChildProcessManager 는 close 이벤트로 감지하고 error 를 만든다:
this.process.on('close', (code: number | null, signal: string | null) => {
logger.error('ChildProcessManager::setupEventHandlers | Child process closed', {
code,
signal
});
const errorMsg = signal
? `Process killed by signal ${signal} (code: ${code})`
: `Process exited with code ${code}`;
this.rejectAllPending(new Error(errorMsg));
this.process = undefined;
this.emit('close', code, signal);
});
기대 동작: refiner 가 정상적으로 process 를 완료하고 결과 파일을 반환.
실제 동작: native 쪽이 SIGSEGV 로 죽고, TypeScript 레이어는 재시도/부분 복구 없이 RefinementService::run | end - {} (빈 error 직렬화) 로 job 을 실패 처리. updateErrorActionJob('refinement') 만 호출되어 job 이 error 상태로 넘어간다.
Log Evidence#
Datadog query (재현용):
service:cupixworks-capture-refinement-arm-instance status:error
service:cupixworks-capture-refinement-arm-instance @job.id:1194561
service:cupixworks-capture-refinement-arm-instance "SIGSEGV"
Crash 순간 (job 1194561, capture 734597):
{
"timestamp": "2026-07-14T03:05:50.589Z",
"status": "error",
"message": "Process killed by signal SIGSEGV (code: null)",
"stack": "Error: Process killed by signal SIGSEGV (code: null)\n at ChildProcess.<anonymous> (/tmp/agent/dist/app.cjs:5248:33)\n at ChildProcess.emit (node:events:524:28)\n at maybeClose (node:internal/child_process:1104:16)\n at ChildProcess._handle.onexit (node:internal/child_process:304:5)",
"job": { "id": 1194561 },
"capture": { "id": 734597 },
"region": "us-west-2",
"host": "b3a90aff006d"
}
Crash 직전 경고 로그 (같은 job):
[2026-07-14 12:05:32] warn [123797.21] | video filepath not found - 693547.insv
[2026-07-14 12:05:32] warn [123794.21] | video filepath not found - 693547.insv
... (수십 회 반복)
[2026-07-14 12:05:47] warn [123197.50] | Empty bim drawing detected. Skip creating grid map.
[2026-07-14 12:05:50] error ChildProcessManager::setupEventHandlers | Child process exited
[2026-07-14 12:05:50] error ChildProcessManager::setupEventHandlers | Child process closed
[2026-07-14 12:05:50] error Process killed by signal SIGSEGV (code: null)
Job 1194562 (capture 734596) — 7초 뒤 동일 stack:
[2026-07-14 12:05:57] error Process killed by signal SIGSEGV (code: null)
14일 통계 — 동일 stack 재발: 2026-07-01 ~ 2026-07-14 사이 15회. 스택트레이스가 두 형태로 관찰됨 (app.cjs:5248 최신, app.cjs:5307 이전 빌드) — 배포 이후에도 native crash 는 재발.
참고: 관련 과거 fix#
git log packages/cupix-capture-refinement-agent/ 에서 ARM64 segfault 이력이 존재 (TSLA-11653 fix: pin aws-cli to 2.33.3 to avoid ARM64 segfault). Native addon 자체는 이 커밋과 별개지만, arm64 환경에서 segfault 가 재발한 전례가 있음.
Hypotheses Considered#
| # | Hypothesis | Evidence for | Evidence against | Verdict |
|---|---|---|---|---|
| H1 | Native ScenemapperApi (Refiner.process()) 가 예외적 입력 상태에서 nil/invalid pointer dereference 로 SIGSEGV |
Stack 이 ChildProcess.emit 에서 끝나고 native 프레임은 노출 안 됨; crash 직전 video filepath not found - 693547.insv 반복 + Empty bim drawing detected; 동일 stack 이 14일간 15회 재현; refinement-service.ts:305 이후 native require(libPath) 로만 진입 |
없음 — TypeScript 코드는 signal 을 보낼 수 없고, fork 자식이 signal 로 종료되는 경우는 native crash 나 OS OOM 두 가지 뿐 |
Confirmed |
| H2 | Node.js executeTimeoutMs 로 인한 SIGKILL 로 잘못 리포트 | child-process.manager.ts:221 은 timeout 시 SIGKILL 을 명시적으로 보내는데, 이 경우 로그에 Execution timeout after {ms}ms warn 이 먼저 남아야 함 |
job 1194561 로그에 timeout warn 없음; signal 이 SIGSEGV 이고 SIGKILL 이 아님 |
Rejected |
| H3 | OOM killer (cgroup) 에 의한 종료 | arm64 instance 에서 리소스 압박 가능성 | OOM 이면 커널이 보통 SIGKILL 을 보내며 로그에 "Killed" (dmesg) 신호도 남음; 여기서는 SIGSEGV. 또한 크래시 직전 로그가 refinement input 관련 경고에 집중돼 있어 메모리 압박 지표와는 무관 | Rejected (uncertain -- OS-level metric 미확인) |
| H4 | 입력 파일 (video 693547.insv, BIM drawing) 누락/손상이 native 쪽 unsafe path 를 트리거 |
Crash 직전 video filepath not found - 693547.insv 가 수십 회, Empty bim drawing detected. Skip creating grid map. 관측; native 코드가 empty geometry 처리를 안전하게 하지 못하면 segfault 가능 |
완전한 증명을 위해서는 native 코어덤프/native log 필요 — 현재는 상관관계 기반 | Confirmed (contributing) |
| H5 | ARM64 환경 특유의 native 라이브러리 버그 (과거 TSLA-11653 유사 회귀) | 서비스 이름 -arm-instance, 과거 aws-cli arm64 segfault fix 이력 |
이번 crash 는 aws-cli 가 아닌 ScenemapperApi 내부 — 동일 회귀는 아님 |
Inconclusive (native 팀 확인 필요) |
Fix Recommendation#
즉시 조치 (Critical)#
- Native 팀에 크래시 리포트 전달:
Refiner.process()내부에서 SIGSEGV 발생. 재현 조건은 (a) 특정 capture 의 video 파일 (693547.insv) 이 refiner 관점에서 not-found, (b) BIM drawing 이 empty. 대상 capture id: 734596, 734597 (2026-07-14), 그 외 동일 stack 발생 job 은 지난 14일 15건. Native 팀이 core dump / minidump 를 확보할 수 있게 arm64 컨테이너에서ulimit -c unlimited및 crash dump 수집 경로를 설정해줄 것. - 입력 검증 강화:
packages/cupix-capture-refinement-agent/src/refinement-service.ts의checkInputFiles(refinement-service.ts:144-154) 는 현재alignment_archive.bin존재만 확인.video filepath not found및 empty BIM drawing 같은 조건도 native 호출 전에 감지하여 job 을 명시적으로 실패시키면 native crash 로 이어지지 않음.runRefinement전에 필수 input 검증 추가 필요 (직접 구현 코드 명시는 생략).
단기 개선 (1주 이내)#
- 자식 프로세스 재시작 없는 hard-fail 개선:
ChildProcessManager는 crash 시 pending 을 reject 하고 종료할 뿐, 재시도 로직이 없다 (child-process.manager.ts:107-120). Native crash 가 입력에 의존적이라면 재시도로 해결 안 되므로 재시도보다 "명확한 error code + job 상태 갱신 + Datadog 알람" 방향이 우선. 현재 catch 블록은RefinementService::run | end - %s로JSON.stringify(error)를 남기는데, 이 값이{}로 찍혀 원인 진단이 어렵다 (관련 커밋:54d03e24b TSLA-12632 fix: pass error directly to logger in RefinementService catch blocks). 이 fix 가 refinement-service.ts:107-110 에도 적용되었는지 확인하고, 안 됐다면 확장.
} catch (error) {
logger.error('RefinementService::run | end - %s', JSON.stringify(error));
await this.jobManager.updateErrorActionJob('refinement');
}
- Repetitive warn log 감축:
video filepath not found - 693547.insv가 수십 회 반복되어 노이즈. Native 팀에 요청하여 한 번만 로깅하도록 하거나, filebeat 레벨에서 sampling.
장기 개선 (재발 방지)#
- Native addon 안정성 테스트 하네스:
ScenemapperApi를 다양한 손상/누락 입력 (missing video, empty BIM, malformed alignment JSON) 에 대해 자동으로 fuzz 실행하는 통합 테스트를 CI 에 추가. Native crash 가 발생하지 않고 명시적 error 를 반환하도록 계약 정의. - arm64 crash dump 상시 수집 파이프라인: 컨테이너 (task definition) 에 core dump 수집 sidecar 또는 volume mount 를 두어, SIGSEGV 발생 시 자동으로 S3 에 업로드. Ad-hoc 디버깅 시간 절감.
- Refiner job idempotency: 현재는 crash 후 자동 재시도가 없다. 입력 파일이 완비되었을 때만 재시도 가능한 idempotent flag 를 job manager 쪽에 추가하면, transient native crash 시 operator 개입 없이 복구 가능.
Monitoring#
- SIGSEGV 재발 알람: 아래 timeseries widget 쿼리로 최근 30분 크래시 수를 표시하고, alert monitor 는 별도 threshold 조건으로 설정.
count:cupixworks-capture-refinement-arm-instance.error{status:error,@message:*SIGSEGV*}.as_count()
Datadog logs 기반 timeseries (dashboard widget) 로 원본 로그를 시계열로 시각화:
logs("service:cupixworks-capture-refinement-arm-instance status:error \"SIGSEGV\"").index("*").rollup("count").by("job.id")
- Native crash 사전 지표:
video filepath not found및Empty bim drawing detected발생률을 대시보드에 추가하여 crash 와의 상관관계 추적.
logs("service:cupixworks-capture-refinement-arm-instance \"Empty bim drawing detected\"").index("*").rollup("count")
- Refinement job 실패율:
jobManager.updateErrorActionJob('refinement')호출 빈도. 서비스 SLO 확보용.
Risk Assessment#
- Risk level: medium — 개별 capture 실패는 격리되지만, 동일 stack 이 14일간 15회 재현되어 특정 tenant/team 의 refinement 파이프라인이 지속적으로 실패 중. 데이터 유실은 없으나 사용자 경험 (미완료 preview / reconstruction) 이 저해됨.
- 예상 복잡도: critical — root cause 가 native C++ addon 내부이며, TypeScript 레이어 fix 만으로는 해결 불가. 입력 검증 강화는 mitigation 이며 fundamental fix 는 native scene-mapper 팀 소관.