ES /docs

AwsS3Manager::downloadParallel | begin - "The specified key does not exist."

RCA: AwsS3Manager::downloadParallel | "The specified key does not exist."

Overview#

What Happened#

2026-04-20 23:26 UTC에 cupixworks-pano-postprocessor-instance 서비스에서 capture 684272 (job 1025631)의 pano 이미지를 S3에서 다운로드하는 과정에서 "The specified key does not exist." 에러가 발생했다. S3에 존재하지 않는 키를 참조하여 다운로드가 실패했고, 이로 인해 후속 mask 처리 단계(MaskWork::maskPanos)에서 빈 이미지로 인한 OpenCV assertion 에러가 연쇄적으로 발생하여 전체 job이 실패했다.

Quick Facts#

Field Value
exception.message "The specified key does not exist."
top_frame aws-s3.manager.ts:50 (downloadParallel)
env production, us-west-2
capture.id 684272
job.id 1025631
team.id 527 (swinerton)
user.email jjohns@swinerton.com

Affected Teams#

Team / Domain Error Count Impact
swinerton 1 (3 log duplicates) capture 684272의 pano postprocessing 전체 실패, 마스킹/리사이즈 미완료

Timeline#

  1. 23:26:00.594ZPanoPostprocessorService::init 시작
  2. 23:26:00.654Z — 인증 완료, run 시작
  3. 23:26:01.951ZAwsS3Manager::downloadParallel에서 S3 NoSuchKey 에러 발생
  4. 23:26:02.199Z — 다운로드 단계 완료 (333ms — 정상 시 5~19초 소요)
  5. 23:26:14.268ZMaskWork::maskPanos에서 빈 이미지로 인한 OpenCV cvtColor assertion 실패
  6. 23:26:15.388ZPanoPostprocessorService::run 실패로 종료 (end - false)
  7. 23:26:16.347Z — 서비스 강제 종료

Error Log#

Datadog Logs

text
AwsS3Manager::downloadParallel | begin - "The specified key does not exist."

Impact#

  • Service: cupixworks-pano-postprocessor-instance
  • Team: swinerton
  • 발생 횟수: 3 (동일 이벤트가 3개의 filebeat agent에서 중복 수집됨 — 실제 에러는 1건)
  • 최초 발생: 2026-04-20T23:26:01.951Z
  • 최근 발생: 2026-04-20T23:26:01.951Z

Root Cause Summary#

Capture 684272의 pano 리소스에 연결된 S3 storage_bucket_key가 실제 S3 버킷에 존재하지 않는다. AwsS3Manager::downloadParallel이 AWS S3에서 해당 키로 이미지를 다운로드하려 했으나 NoSuchKey 에러를 받았다. 이 에러는 downloadParallel 내부의 try/catch 블록(aws-s3.manager.ts:75-77)에서 catch되어 로그만 남기고 조용히 무시되었다. 그 결과 다운로드 디렉토리에 이미지 파일이 생성되지 않았고, 후속 MaskWork::maskPanos 단계에서 빈 이미지를 OpenCV cvtColor로 처리하려다 assertion failure가 발생하여 전체 job이 실패했다.

S3 키가 존재하지 않는 원인은 두 가지 가능성이 있다: (1) pano 리소스의 storage_bucket_key가 잘못 설정되었거나, (2) S3 객체가 업로드 전 또는 삭제 후에 참조되었다. 동일 시간대 동일 팀의 다른 job들은 정상 처리되었으므로 capture 684272 특정 데이터 문제로 판단된다.

Technical Analysis#

Code Path#

  1. Entry point: pano-postprocessor-service.ts:43init()authenticate()run()

  2. Pano 목록 조회: pano-postprocessor-service.ts:96에서 getCPPanosByCaptureId(captureId)를 호출하여 capture 684272에 속한 pano 목록을 가져온다.

pano-postprocessor-manager.ts:29-32typescript
async getCPPanosByCaptureId(captureId: number): Promise<CPPano[]> {
    const srvPanos = await this.cupixApi.pano.getAll(captureId);
    return srvPanos.filter((srvPano) => srvPano.state !== 'done').map((srvPano) => new CPPano(srvPano));
};
  1. CPPano 모델 생성: cppano.ts:23-40에서 API 응답의 resources[0]에서 S3 버킷 정보를 추출한다. storage_bucket_key가 S3 키로 사용된다.
cppano.ts:32-35typescript
this._panoBucketRegion = pano.resources[0]['s3_bucket_region'];
this._panoBucketName = pano.resources[0]['s3_source_bucket_name'];
this._panoBucketKey = pano.resources[0]['storage_bucket_key'];
this._panoBucketEndpoint = pano.resources[0]['bucket_endpoint'];
  1. 다운로드 실행: pano-postprocessor-service.ts:117에서 downloadParallel(cpPanos)를 호출한다.
aws-s3.manager.ts:60-77typescript
const tasks = cpPano.map(cpPano => {
    return limit(async () => {
        try {
            logger.debug('AwsS3Manager::downloadParallel | buket region, name, key, endpoint, download path %s %s %s %s %s', cpPano.panoBucketRegion, cpPano.panoBucketName, cpPano.panoBucketKey, cpPano.panoBucketEndpoint, cpPano.downloadImagePath);

            if (cpPano.panoBucketEndpoint) {
                await this.downloadByPanoApi(cpPano);
            } else {
                await this.download(
                    cpPano.panoBucketRegion!,
                    cpPano.panoBucketName!,
                    cpPano.panoBucketKey!,
                    cpPano.downloadImagePath!
                );
            }
        } catch (err) {
            logger.error('AwsS3Manager::downloadParallel | download failed - pano: %s, error: %s', cpPano.downloadImagePath, (err as Error).message);
        }
    });
});
  1. Failure point: aws-s3.manager.ts:68-73this.download()가 S3 getObject를 호출할 때 NoSuchKey 에러를 받는다. 이 에러는 line 75-77의 catch 블록에서 잡히고 로그만 남긴다.
aws-s3.manager.ts:29-36typescript
const stream = s3.getObject(params).createReadStream();
const writeStream = fs.createWriteStream(downloadPath);

return new Promise((resolve, reject) => {
    stream.on('error', (err) => {
        writeStream.destroy();
        reject(err);
    });
  1. 연쇄 실패: 다운로드가 실패해도 downloadParallel은 정상 완료된다 (에러가 catch되어 무시됨). 이후 maskPanos가 빈 이미지 파일에 대해 OpenCV cvtColor을 실행하다 !_src.empty() assertion failure가 발생한다.
pano-postprocessor-service.ts:117-126typescript
await this.awsS3Manager.downloadParallel(cpPanos);
this.panoPostprocessorManager.logElapsedTime(start, 'download_panos');

// mask
if (maskTypeOption) {
    this.maskWork.createOptionFile(optionPath, maskTypeOption);
    start = Date.now();
    await this.maskWork.maskPanos(downloadDir, maskDir!, optionPath);

기대 동작: S3에서 pano 이미지를 다운로드한 후 후속 처리 단계 진행. 실제 동작: S3 키가 존재하지 않아 다운로드 실패. 에러가 조용히 무시되어 빈 파일 상태로 후속 처리가 진행되었고 OpenCV에서 crash.

Log Evidence#

Datadog에서 사용한 쿼리:

text
service:cupixworks-pano-postprocessor-instance status:error @environment:production "AwsS3Manager::downloadParallel"
text
service:cupixworks-pano-postprocessor-instance @environment:production @capture.id:684272

에러 발생 전후 job 타임라인 (job 1025631, capture 684272):

text
23:26:00.594 [info]  PanoPostprocessorService::init
23:26:00.595 [info]  PanoPostprocessorService::authenticate | begin
23:26:00.653 [info]  CupixAuth::setSession | session_id: 240d9c05e37a267c241002f3383af770001f012c
23:26:00.654 [info]  PanoPostprocessorService::authenticate | end
23:26:00.654 [info]  PanoPostprocessorService::run | begin
23:26:01.951 [error] AwsS3Manager::downloadParallel | begin - "The specified key does not exist."
23:26:02.199 [info]  PanoPostprocessorService Elapsed Time - dd_step:download_panos&dd_elapsed_time:333ms
23:26:14.268 [error] MaskWork::maskPanos | script Traceback (most recent call last): ... cv2.error: (-215:Assertion failed) !_src.empty() in function 'cvtColor'
23:26:15.036 [error] MaskWork::maskPanos | error code:1
23:26:15.388 [error] PanoPostprocessorService::run | end - false
23:26:16.347 [info]  PanoPostprocessorService::terminateService | force shutdown after 10 seconds

핵심 관찰:

  • 다운로드 단계가 333ms에 완료됨 (정상 job은 5~19초). 이는 S3 다운로드가 즉시 실패했음을 의미함.
  • 동일 세션 ID(240d9c05...)로 동일 시간대에 실행된 다른 job들은 정상 완료됨 — 인증 문제가 아님.
  • 3건의 로그는 동일 이벤트가 3개의 filebeat agent 호스트(5f1e305e0586, 897bdb7c69f7, e3f78659ff55)에서 중복 수집된 것.
  • 90분 검색 윈도우 내 이 에러는 capture 684272에서만 발생.

Hypotheses Considered#

# Hypothesis Evidence for Evidence against Verdict
H1 S3 키(storage_bucket_key)가 존재하지 않는 객체를 가리킴 — pano 리소스 데이터 불일치 AWS S3 NoSuchKey 에러 메시지, 다운로드 333ms 즉시 실패, 동일 시간대 다른 job 정상 완료 Confirmed
H2 AWS S3 인증/권한 문제로 다운로드 실패 에러 메시지가 NoSuchKey이지 AccessDenied가 아님, 동일 세션의 다른 job들 정상 작동 Rejected
H3 S3 리전 불일치 (잘못된 리전으로 요청) 리전 불일치 시 PermanentRedirect 또는 AuthorizationHeaderMalformed 에러가 발생하며 NoSuchKey가 아님, 동일 리전의 다른 job 정상 Rejected
H4 일시적 S3 장애 (eventual consistency) S3 eventual consistency로 최근 업로드된 객체가 일시적으로 보이지 않을 수 있음 AWS S3는 2020년 12월부터 strong read-after-write consistency 제공, 동일 시간대 다른 다운로드 정상 Rejected

Fix Recommendation#

즉시 조치 (Critical)#

  • Capture 684272의 pano 리소스를 DB에서 확인하여 storage_bucket_key가 실제 S3 객체와 일치하는지 검증. 키가 잘못된 경우 올바른 값으로 수정하거나, 해당 capture를 재처리.
  • 개별 pano 다운로드 실패 건에 대해 해당 pano를 error state로 마킹하도록 downloadParallel의 catch 블록 수정 필요 (aws-s3.manager.ts:75-77). 현재는 에러를 로깅만 하고 무시하여 후속 단계에서 연쇄 실패가 발생한다.

단기 개선 (1주 이내)#

  • downloadParallel 메서드에서 다운로드 실패한 pano를 추적하여 반환하도록 변경. pano-postprocessor-service.ts:117 호출부에서 실패한 pano를 후속 처리(mask, infer, resize)에서 제외하는 로직 추가.
  • 다운로드 단계 완료 후, 다운로드된 파일이 실제로 존재하고 크기가 0보다 큰지 검증하는 단계 추가.

장기 개선 (재발 방지)#

  • Pano 리소스 생성 시 S3 headObject를 호출하여 키 존재 여부를 검증하는 validation 추가 (upstream 서비스).
  • downloadParallel에 retry 로직 추가 — NoSuchKey는 retry 불필요하지만, 네트워크 에러나 throttling에 대해서는 exponential backoff retry가 유용.

Monitoring#

  • 다운로드 단계 소요 시간이 비정상적으로 짧은 경우 (예: 1초 미만) 알림 추가:
text
service:cupixworks-pano-postprocessor-instance "dd_step:download_panos" "dd_elapsed_time"
  • S3 NoSuchKey 에러 모니터링:
text
service:cupixworks-pano-postprocessor-instance status:error "The specified key does not exist"

Risk Assessment#

  • Risk level: low
  • 예상 복잡도: standard
  • 이 에러는 capture 684272에 국한된 데이터 문제이며, 동일 시간대 다른 job에는 영향 없음. 그러나 downloadParallel의 에러 무시 패턴은 향후 유사한 연쇄 실패를 유발할 수 있어 코드 수정이 권장됨.