ES /docs

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#

  1. 2026-07-14 12:05:28 KST — job 1194561 시작 (RefinementService::init, authenticate, run | begin).
  2. 2026-07-14 12:05:32 KST — 수십 건의 video filepath not found - 693547.insv 경고, Empty bim drawing detected. Skip creating grid map. 경고.
  3. 2026-07-14 12:05:50 KST — job 1194561 자식 프로세스 SIGSEGV 로 종료 (ChildProcessManager::setupEventHandlers | Child process closed/exited, capture 734597, host b3a90aff006d).
  4. 2026-07-14 12:05:57 KST — job 1194562 도 동일 원인으로 SIGSEGV (capture 734596, host 812624bde753).
  5. 2026-07-14 12:05:51 KSTRefinementService::terminateService | force shutdown after 10 seconds 로그 이후 프로세스 종료.

Error Log#

Datadog Logs

text
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 은 ScenemapperManagerfork() 로 띄운 자식 프로세스에서 native scene-mapper library (ScenemapperApi, require(libPath) 로 dynamic load) 의 Refiner.process() 를 호출한다. 이 native C++ 코드가 SIGSEGV 로 크래시하여 부모 프로세스에 close(null, 'SIGSEGV') 이벤트가 발생하고, ChildProcessManagerProcess 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 .node addon 내부 (Datadog 로그에는 native stack 이 노출되지 않음)

runRefinement 은 refiner 를 실행하기 전에 log watcher 를 열고 execute 호출로 IPC 를 통해 native 쪽에서 Refiner.process() 를 트리거한다:

packages/cupix-capture-refinement-agent/src/refinement-service.ts:305-318typescript
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() 를 실행한다:

packages/cupix-capture-refinement-agent/src/process/scenemapper.process.ts:36-48typescript
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 로 죽으면 부모의 ChildProcessManagerclose 이벤트로 감지하고 error 를 만든다:

packages/base/src/manager/child-process.manager.ts:107-120typescript
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 (재현용):

text
service:cupixworks-capture-refinement-arm-instance status:error
text
service:cupixworks-capture-refinement-arm-instance @job.id:1194561
text
service:cupixworks-capture-refinement-arm-instance "SIGSEGV"

Crash 순간 (job 1194561, capture 734597):

json
{
  "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):

text
[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:

text
[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.tscheckInputFiles (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 - %sJSON.stringify(error) 를 남기는데, 이 값이 {} 로 찍혀 원인 진단이 어렵다 (관련 커밋: 54d03e24b TSLA-12632 fix: pass error directly to logger in RefinementService catch blocks). 이 fix 가 refinement-service.ts:107-110 에도 적용되었는지 확인하고, 안 됐다면 확장.
packages/cupix-capture-refinement-agent/src/refinement-service.ts:107-110typescript
} 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 조건으로 설정.
text
count:cupixworks-capture-refinement-arm-instance.error{status:error,@message:*SIGSEGV*}.as_count()

Datadog logs 기반 timeseries (dashboard widget) 로 원본 로그를 시계열로 시각화:

text
logs("service:cupixworks-capture-refinement-arm-instance status:error \"SIGSEGV\"").index("*").rollup("count").by("job.id")
  • Native crash 사전 지표: video filepath not foundEmpty bim drawing detected 발생률을 대시보드에 추가하여 crash 와의 상관관계 추적.
text
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 팀 소관.