ImageCPObject::downloadFile | response path: /tmp/workspace/cl05fno4p2re/cl05fno4p2re.png, code: 404
RCA: ImageCPObject::downloadFile | response path: /tmp/workspace/cl05fno4p2re/cl05fno4p2re.png, code: 404
Error Log#
ImageCPObject::downloadFile | response path: /tmp/workspace/cl05fno4p2re/cl05fno4p2re.png, code: 404, message: Not Found
Impact#
- Service:
cupixworks-any-thumbnail-agent - Team: tpc
- 발생 횟수: 1
- 최초 발생: 2026-04-11T04:41:19.293Z
- 최근 발생: 2026-04-11T04:41:19.293Z
Root Cause Summary#
CPAttachment.setModel() 에서 attachable type 문자열을 API URL 경로로 변환할 때 CamelCase → snake_case 변환 없이 단순히 .toLowerCase() + 's'를 적용합니다. RevisionRequest 타입의 경우 revisionrequests가 생성되지만, Rails 라우트는 revision_requests (snake_case)를 사용합니다. 이로 인해 썸네일 에이전트가 첨부파일 원본을 다운로드할 때 잘못된 URL 경로로 요청하여 API가 404를 반환합니다. 단일 단어 타입(Annotation, Texture)은 정상 동작하지만, 복합 단어 타입(RevisionRequest, WorkItem)은 모두 동일한 문제를 가지고 있습니다.
Technical Analysis#
Code Path#
- Entry point:
thumbnail-service.ts:58—ThumbnailService.run()이 SQS 메시지를 받아 실행 thumbnail-service.ts:94-103—newModel()에서params.type이"Attachment"이면CPAttachment인스턴스 생성thumbnail-service.ts:75—supportModel.setModel()호출- Failure point:
cpattachment.ts:38— attachable type을 URL 경로로 변환하는 로직
// cpattachment.ts:37-40
const attachableId = this.modelAttachable.id.toString();
const attachableType = this.modelAttachable.type.toLowerCase() + 's';
const baseEndPoint = Environment.CPX_API_ENDPOINT + '/' + attachableType + '/' + attachableId + '/attachments/' + this.modelKey;
attachable.type이 "RevisionRequest"인 경우:
- 기대 동작:
revision_requests(Rails snake_case 라우트와 일치) - 실제 동작:
revisionrequests(CamelCase를 단순 lowercase, underscore 누락)
생성된 URL: http://api-tesla.cupix.internal/api/v1/revisionrequests/10/attachments/cl05fno4p2re/download
정상 URL: http://api-tesla.cupix.internal/api/v1/revision_requests/10/attachments/cl05fno4p2re/download
thumbnail-service.ts:77—supportModel.downloadOriginal()호출image-cpobject.ts:164-178—downloadOriginal()에서_downloadOriginalFileUrl사용하여 다운로드 시도
// image-cpobject.ts:164-178
downloadOriginal = async (): Promise<void> => {
logger.debug('ImageCPObject::downloadOriginal | begin');
logger.info('ImageCPObject::downloadOriginal | url: %s, path: %s', this._downloadOriginalFileUrl, this._originalFilePath);
if (this._downloadOriginalFileUrl == undefined || this._originalFilePath == undefined) {
logger.error('ImageCPObject::downloadOriginal | end - undefined url or path');
return;
}
// ...
await this.downloadFile(this._downloadOriginalFileUrl, this._originalFilePath);
};
image-cpobject.ts:73-77—downloadFile()에서 응답 status code 404 수신, 에러 로그 출력
// image-cpobject.ts:73-77
sendReq
.on('response', res => {
if (res.statusCode !== 200) {
logger.error('ImageCPObject::downloadFile | response path: %s, code: %d, message: %s', filePath, res.statusCode, res.statusMessage);
reject(cupixAuth.handleError(res));
}
})
Rails 라우트는 revision_requests만 인식합니다:
# tesla/config/routes.rb:1840-1842
resources :revision_requests, only: %i[create] do
concerns :attachments
end
Log Evidence#
사용한 Datadog 쿼리:
service:cupixworks-any-thumbnail-agent "cl05fno4p2re"
Time range: 2026-04-11T03:41:00Z to 2026-04-11T05:11:00Z
"cl05fno4p2re"
Time range: 2026-04-11T03:41:00Z to 2026-04-11T05:11:00Z
이벤트 타임라인:
| 시간 (KST) | 이벤트 | 서비스 |
|---|---|---|
| 13:38:07 | Attachment cl05fno4p2re 생성 (model_id: 27536, attachable: RevisionRequest#10) |
event-service |
| 13:38:08 | POST /api/v1/revision_requests/10/attachments/cl05fno4p2re/upload_url → 200 |
cupixworks-api |
| 13:38:12 | PUT /api/v1/revision_requests/10/attachments/cl05fno4p2re/check_uploading → 200 |
cupixworks-api |
| 13:41:19 | ImageCPObject::downloadOriginal — URL: .../revisionrequests/10/attachments/cl05fno4p2re/download |
thumbnail-agent |
| 13:41:19 | [404] GET /api/v1/revisionrequests/10/attachments/cl05fno4p2re/download (ApiController#routing_error) |
cupixworks-api |
| 13:41:19 | ImageCPObject::downloadFile — code: 404, message: Not Found |
thumbnail-agent |
| 13:41:20 | [200] GET /api/v1/annotations/10/attachments/cl05fno4p2re — 정상 조회 (다른 경로) |
cupixworks-api |
핵심 로그:
썸네일 에이전트가 잘못된 URL로 다운로드를 시도한 info 로그:
ImageCPObject::downloadOriginal | url: http://api-tesla.cupix.internal/api/v1/revisionrequests/10/attachments/cl05fno4p2re/download, path: /tmp/workspace/cl05fno4p2re/cl05fno4p2re.png
API 서버에서 해당 경로를 routing_error로 처리한 로그:
[404] GET /api/v1/revisionrequests/10/attachments/cl05fno4p2re/download (ApiController#routing_error)
업로드 시에는 정상 경로(revision_requests)를 사용하여 성공한 로그:
[200] POST /api/v1/revision_requests/10/attachments/cl05fno4p2re/upload_url (Api::V1::AttachmentsController#upload_url)
[200] PUT /api/v1/revision_requests/10/attachments/cl05fno4p2re/check_uploading (Api::V1::AttachmentsController#check_uploading)
Attachment 생성 이벤트에서 확인된 모델 정보:
{
"key": "cl05fno4p2re",
"name": "스크린샷 2026-04-11 오후 1.37.55.png",
"attachment_type": null,
"state": "created",
"model_type": "Attachment",
"model_id": 27536
}
Fix Recommendation#
즉시 조치 (Critical)#
- 수정 파일:
applications/agents/packages/cupix-tesla-thumbnail-agent/src/model/cpattachment.ts:38 attachable.type을 URL 경로로 변환할 때 CamelCase → snake_case 변환을 적용해야 합니다."RevisionRequest"→"revision_request"→"revision_requests","WorkItem"→"work_item"→"work_items"형태로 변환해야 Rails 라우트와 일치합니다.- 현재
this.modelAttachable.type.toLowerCase() + 's'부분을 CamelCase를 snake_case로 변환하는 로직으로 교체하면 됩니다 (예: 대문자 앞에_삽입 후 전체 lowercase).
단기 개선 (1주 이내)#
- 다른 attachable type들도 동일한 패턴인지 검증이 필요합니다.
WorkItem,RevisionRequest등 복합 단어 타입이 모두 영향을 받으며, 이들의 attachment 썸네일 생성이 모두 실패할 수 있습니다. - upload 경로(
upload_url,check_uploading)가 정상 동작하는 것으로 보아, upload 쪽은 다른 코드 경로를 사용하거나 API client가 올바른 경로를 생성하고 있을 수 있습니다. upload 경로와의 일관성을 확인해야 합니다.
장기 개선 (재발 방지)#
- API endpoint URL을 각 모델에서 직접 문자열 조합으로 생성하는 대신, API client 라이브러리에서 중앙 관리하도록 리팩토링하는 것을 고려할 수 있습니다.
- attachable type → URL path 매핑을 명시적 매핑 테이블로 관리하면 타입 추가 시 실수를 방지할 수 있습니다.
Monitoring#
- 추가할 메트릭/알림:
cupixworks-any-thumbnail-agent서비스에서downloadFile404 에러 발생 시 알림 - Datadog 쿼리:
service:cupixworks-any-thumbnail-agent status:error "downloadFile" "404"
Risk Assessment#
- Risk level: medium
- 예상 복잡도: trivial —
cpattachment.ts:38한 줄 수정으로 해결 가능