FileSystemManager::loadSkatResults | end - not found file - /efs/a0504a63e1595b88/skatmaster/results
RCA: FileSystemManager::loadSkatResults — capture_alignments.json not found
Overview#
What Happened#
2026-04-22 13:17~13:20 UTC 사이 cupixworks-capture-postprocessor-agent에서 5건의 에러가 발생했다. postprocessor agent가 EFS 상의 skatmaster/results/capture_alignments.json 파일을 읽으려 했으나 파일이 존재하지 않아 처리에 실패했다. 5건은 3개 팀(lemartec, futsu, whitingturner/rsconstruction), 2개 리전(us-west-2, ap-southeast-1)에 걸쳐 서로 다른 capture에서 발생했으며, 각 실패 후 BaseService::handlingMessageErrors에 의해 SQS 메시지가 에러 처리되었다. 대표 에러인 capture 683964의 경우, upstream에서 이미 에러 코드 AGT1201이 설정되어 있었고 SKAT이 alignment 결과를 생성하지 않았음에도 postprocessor가 트리거되었다.
Quick Facts#
| Field | Value |
|---|---|
| exception.message | FileSystemManager::loadSkatResults | end - not found file - /efs/{hash}/skatmaster/results/capture_alignments.json |
| top_frame | packages/cupix-capture-postprocessor-agent/src/manager/file-system.manager.ts:229 |
| env | production, us-west-2, ap-southeast-1 |
Affected Teams#
| Team / Domain | Error Count | Impact |
|---|---|---|
| lemartec | 1 | capture 683964 postprocessing 실패 (error code AGT1201) |
| futsu | 1 | capture 1782 postprocessing 실패 (ap-southeast-1) |
| whitingturner | 2 | capture 684676, 684675 postprocessing 실패 |
| rsconstruction | 1 | capture 684637 postprocessing 실패 |
Timeline#
- 2026-04-22T13:17:15Z — 최초 에러 발생 (EFS path:
a0504a63e1595b88) - 2026-04-22T13:18:45Z — 두 번째 에러 (EFS path:
5ddfd1ddad055ad5) - 2026-04-22T13:20:20-25Z — 세 건 연속 에러 (EFS paths:
8dd318811e13d33c,baf3b2c7b31bb1c2,414cc7a32da9f924) - 2026-04-22T13:43~Z — 동일 시간대의 다른 capture들은
loadSkatResults성공 (info 로그 확인)
Error Log#
FileSystemManager::loadSkatResults | end - not found file - /efs/a0504a63e1595b88/skatmaster/results/capture_alignments.json
Impact#
- Service:
cupixworks-capture-postprocessor-agent - Team: lemartec
- 발생 횟수: 5
- 최초 발생: 2026-04-22T13:17:15.928Z
- 최근 발생: 2026-04-22T13:20:25.336Z
Root Cause Summary#
Postprocessor agent가 capture_alignments.json이 EFS에 존재하지 않는 상태에서 SQS 메시지를 받아 처리를 시작했다. 대표 에러(capture 683964)의 cross-service 로그 분석 결과, 해당 capture는 이미 upstream에서 에러 코드 AGT1201이 설정되어 있었으며 "3D reconstruction was skipped due to the existence of an capture error code"라는 로그가 확인된다. 즉, skatmaster가 alignment 결과를 생성하지 않았음에도 postprocessor가 트리거된 것이다. Postprocessor의 run() 메서드(line 91-99)는 loadSkatMasterResults()로 processing_status.json을 먼저 로드하고, cpCapture.errorCode 체크(line 92)를 통과한 후 loadSkatResults()에서 capture_alignments.json을 읽는다. 그러나 skatmaster가 에러로 인해 alignment 계산을 건너뛴 경우, processing_status.json은 존재하되 capture_alignments.json은 미생성 상태이므로 여기서 실패한다. 이는 upstream 에러 상태의 capture에 대해 postprocessor가 불필요하게 트리거되는 문제와, processing_status.json 내 에러 상태를 loadSkatResults 호출 전에 충분히 검증하지 못하는 문제의 복합이다.
Technical Analysis#
Code Path#
- Entry point:
postprocessor-service.ts:64—run()메서드가 SQS 메시지로부터 호출 postprocessor-service.ts:87—fileSystemManager.setEfsPath(cpCapture)— capture의 EFS 경로 설정postprocessor-service.ts:91—fileSystemManager.loadSkatMasterResults(cpCapture)—processing_status.json로드 (성공)postprocessor-service.ts:99—fileSystemManager.loadSkatResults(cpCapture, this.actionName)— alignment 결과 로드 시도- Failure point:
file-system.manager.ts:228-230—capture_alignments.json파일 존재 여부 확인 후 에러 로그 출력 및 reject
const fileSystemManager = new FileSystemManager(Environment.DEBUG_MODE);
fileSystemManager.setErrorCode = (errorCode: string) => this.jobManager.setErrorCode(errorCode);
fileSystemManager.setEfsPath(cpCapture);
fileSystemManager.makeEfsDirectory();
await fileSystemManager.loadCPCaptureModel(cpCapture);
await fileSystemManager.loadCPCaptureModelFromVideoDecodingResult(cpCapture);
await fileSystemManager.loadSkatMasterResults(cpCapture);
if (cpCapture.errorCode !== '') {
this.jobManager.setErrorCode(cpCapture.errorCode);
const msg = `PostprocessorService::run - found skat-master error code - ${cpCapture.errorCode}`;
logger.error(msg);
throw new Error(msg);
}
await fileSystemManager.loadSkatResults(cpCapture, this.actionName);
loadSkatResults 내부에서 capture_alignments.json (DefaultSkatSampledJsonFileName)은 필수 파일로 취급되며, 파일이 없으면 즉시 reject된다:
// Sampled Results
const skatSampledResultsFilePath = path.join(this.skatMasterDirPath, Constants.DefaultResultsDirName, Constants.DefaultSkatMasterFileName);
if (CPUtils.getFileSize(skatSampledResultsFilePath) === -1) {
logger.error('FileSystemManager::loadSkatResults | end - not found file - %s', skatSampledResultsFilePath);
return reject();
}
상수 정의에서 DefaultSkatSampledJsonFileName = 'capture_alignments.json' (constants.ts:21)으로, 이 파일은 SKAT alignment 계산의 최종 output이다.
기대 동작: SKAT 처리가 완전히 완료된 후 postprocessor가 트리거되어 모든 결과 파일이 EFS에 준비된 상태에서 읽힘. 실제 동작: SKAT 처리 중간(processing_status.json은 존재하지만 capture_alignments.json은 아직 미생성) 시점에 postprocessor가 트리거됨.
Log Evidence#
사용한 Datadog 쿼리:
service:cupixworks-capture-postprocessor-agent status:error "loadSkatResults"
Time: 2026-04-22T12:17:00Z ~ 2026-04-22T13:50:00Z
5건의 에러 로그 — 모두 서로 다른 EFS 경로에서 동일 패턴 발생:
2026-04-22 22:17:15 KST | error | FileSystemManager::loadSkatResults | end - not found file - /efs/a0504a63e1595b88/skatmaster/results/capture_alignments.json
2026-04-22 22:18:45 KST | error | FileSystemManager::loadSkatResults | end - not found file - /efs/5ddfd1ddad055ad5/skatmaster/results/capture_alignments.json
2026-04-22 22:20:20 KST | error | FileSystemManager::loadSkatResults | end - not found file - /efs/8dd318811e13d33c/skatmaster/results/capture_alignments.json
2026-04-22 22:20:23 KST | error | FileSystemManager::loadSkatResults | end - not found file - /efs/baf3b2c7b31bb1c2/skatmaster/results/capture_alignments.json
2026-04-22 22:20:25 KST | error | FileSystemManager::loadSkatResults | end - not found file - /efs/414cc7a32da9f924/skatmaster/results/capture_alignments.json
각 에러 직후 BaseService::handlingMessageErrors 로그가 "undefined error"로 기록됨:
2026-04-22 22:17:17 KST | error | BaseService::handlingMessageErrors | Error and message object - {"error":"undefined error","sqsMessage":{"MessageId":"2c76eed8-3419-4544-8d9a-b2a77fd2e03d","Attributes":{"ApproximateReceiveCount":"1"}}}
동일 시간대의 다른 capture들은 약 25분 후 성공:
service:cupixworks-capture-postprocessor-agent status:info "loadSkatResults"
2026-04-22 22:43:23 KST | info | FileSystemManager::loadSkatResults | read file meta - created at: Wed Apr 22 13:37:54 2026 GMT, skatSDK: 3.30.4
2026-04-22 22:44:36 KST | info | FileSystemManager::loadSkatResults | read file meta - created at: Wed Apr 22 13:32:27 2026 GMT, skatSDK: 3.30.4
성공한 capture들의 capture_alignments.json의 created 필드는 13:3213:39 UTC로, 에러 발생 시점(13:1713:20)보다 이후이다. 이는 에러 발생 시점에 SKAT alignment 계산이 아직 진행 중이었음을 확인시켜준다.
"skat-master error code" 검색 결과 0건이므로, loadSkatMasterResults() (processing_status.json)는 모든 케이스에서 성공적으로 로드되었다. 그러나 processing_status.json 로드 성공이 alignment 결과 존재를 보장하지는 않는다.
Cross-service 로그 (capture 683964 관련):
"683964" (all services)
Time: 2026-04-22T13:17:00Z ~ 2026-04-22T13:18:00Z
2026-04-22 13:17:15.268Z | info | BaseService::runByMessage | id: 1024816
2026-04-22 13:17:15.315Z | info | JobManager::loadJob | begin - job id: 1024816
2026-04-22 13:17:15.357Z | info | JobManager::loadJob | end - job id: 1024816
2026-04-22 13:17:15.928Z | error | FileSystemManager::loadSkatResults | end - not found file - .../capture_alignments.json
2026-04-22 13:17:17.061Z | info | create editing entity on Capture 683964
2026-04-22 13:17:17.062Z | info | Analysis skipped: error_code=AGT1201. capture_id: 683964
2026-04-22 13:17:17.062Z | info | 3D reconstruction was skipped due to the existence of an capture error code. capture_id: 683964, error_code: AGT1201
2026-04-22 13:17:17.062Z | info | capture 683964 publish skipped: error_code(AGT1201) exist
이 로그는 capture 683964가 이미 에러 상태(AGT1201)였음을 확인한다. Skatmaster가 해당 capture에 대해 alignment 계산을 실행하지 않았기 때문에 capture_alignments.json이 EFS에 생성되지 않았다. 그럼에도 postprocessor SQS 메시지가 전달되어 처리가 시도되었다.
5건의 에러에 대한 상세 정보:
| Timestamp (UTC) | EFS Path | Capture ID | Job ID | Team | Region |
|---|---|---|---|---|---|
| 13:17:15 | a0504a63e1595b88 |
683964 | 1024816 | lemartec | us-west-2 |
| 13:18:45 | 5ddfd1ddad055ad5 |
1782 | 6453 | futsu | ap-southeast-1 |
| 13:20:20 | 8dd318811e13d33c |
684676 | 1027060 | whitingturner | us-west-2 |
| 13:20:23 | baf3b2c7b31bb1c2 |
684637 | 1027012 | rsconstruction | us-west-2 |
| 13:20:25 | 414cc7a32da9f924 |
684675 | 1027056 | whitingturner | us-west-2 |
Hypotheses Considered#
| # | Hypothesis | Evidence for | Evidence against | Verdict |
|---|---|---|---|---|
| H1 | Upstream 에러 상태(AGT1201)의 capture에 대해 postprocessor가 불필요하게 트리거됨 | capture 683964의 cross-service 로그: "Analysis skipped: error_code=AGT1201", "3D reconstruction was skipped" — skatmaster가 alignment을 생성하지 않음 |
나머지 4건의 capture에 대해서는 AGT1201 여부 미확인 (로그 부재) | Confirmed (대표 에러) |
| H2 | SKAT 처리 완료 전 postprocessor 조기 트리거 (race condition) | 동일 시간대 성공한 capture들의 파일 created 시각(13:32-13:39)이 에러 시점(13:17-13:20)보다 이후, processing_status.json은 존재함 | capture 683964는 AGT1201로 인해 alignment 자체가 미실행 — 단순 타이밍 문제가 아닌 에러 상태 문제 | Confirmed (일부 케이스) |
| H3 | EFS mount 문제로 파일 접근 불가 | — | 같은 EFS 상의 processing_status.json은 정상 로드됨, 5건 모두 서로 다른 EFS 경로이므로 단일 mount 문제 아님 | Rejected |
| H4 | SQS 메시지 중복 또는 순서 문제 | — | 모든 에러의 ApproximateReceiveCount가 "1"로 첫 번째 수신 | Rejected |
Fix Recommendation#
즉시 조치 (Critical)#
postprocessor-service.ts:92—cpCapture.errorCode체크 이후에도loadSkatResults호출 전에 capture의 upstream 에러 상태(예:AGT1201)를 추가 검증하는 guard 추가. Capture가 이미 에러 상태이면 alignment 로드를 건너뛰고 에러 처리 경로로 이동하도록 변경.file-system.manager.ts:229— 에러 로그 레벨을warn으로 하향 검토. Upstream 에러로 인한 파일 부재는 시스템 버그가 아닌 expected failure이므로error가 과도할 수 있음.
단기 개선 (1주 이내)#
loadSkatMasterResults에서 로드한processing_status.json의 내용을 검사하여, SKAT 처리가 alignment 단계까지 도달했는지 확인하는 readiness check 추가. 에러 상태로 종료된 경우loadSkatResults호출을 skip.- Upstream에서 에러 코드가 있는 capture에 대해 postprocessor SQS 메시지 전송을 억제하는 방안 검토.
장기 개선 (재발 방지)#
- SKAT 처리 완료 상태를 명확히 구분하는 마커 파일 또는
processing_status.json내 phase 필드를 활용하여, postprocessor가 각 결과 파일의 존재 여부를 사전에 판단할 수 있도록 프로토콜 정립. - Upstream 시스템(SKAT/scenemapper)에서 postprocessor SQS 메시지 전송 시점을 모든 결과 파일 write 완료 이후로 보장하거나, 에러 시 postprocessor 트리거를 하지 않도록 조율.
Monitoring#
- 추가할 메트릭:
capture_alignments.json파일 누락 빈도 추적 - Datadog 쿼리:
service:cupixworks-capture-postprocessor-agent "loadSkatResults | end - not found file"
- 파일 미발견 에러가 SQS 재처리 후 성공하는 비율을 모니터링하여, 단순 타이밍 문제인지 영구적 실패인지 구분
Risk Assessment#
- Risk level: medium
- 예상 복잡도: standard — retry 로직 추가 또는 로그 레벨 변경은 비교적 간단하나, upstream 타이밍 보장은 cross-service 조율 필요