BaseService::handlingMessageErrors | Error and message object - {"error":"undefined response","sqsMe
RCA: BaseService::handlingMessageErrors — "undefined response" (Lens covered video)
Overview#
What Happened#
cupixworks-capture-preprocessor-agent 가 SQS 메시지를 처리하던 중 PreprocessorService.checkSupportedVideo 의 도메인 검증에서 "Lens covered video detected." Error 가 발생했고, BaseService::handlingMessageErrors 가 이 에러의 원인을 식별하지 못해 error: "undefined response" 형태의 에러 로그를 남겼다. 2026-06-25 05:30 KST 와 06:19 KST 두 차례 발생했으며, 클러스터 fingerprint 기준 24시간 내 같은 패턴(빈 error.response)으로만 따지면 3회까지 관측된다.
Quick Facts#
| Field | Value |
|---|---|
| exception.class | Error (plain new Error(reason)) |
| exception.message | Lens covered video detected. |
| top_frame | packages/cupix-capture-preprocessor-agent/src/preprocessor-service.ts:865 |
| logged as | BaseService::handlingMessageErrors | Error and message object - {"error":"undefined response", ...} |
| env | production, us-west-2 |
Affected Teams#
| Team / Domain | Error Count | Impact |
|---|---|---|
| mortenson / capture preprocessing | 2 | "lens covered" 검증에 걸린 capture 의 실패 원인이 로그에서 "undefined response" 로만 보이므로, 운영자가 외부 의존성 문제로 오인할 수 있음. 실제 capture 처리 자체는 정상적으로 실패 처리된다. |
Timeline#
- 2026-06-25 05:30:20 KST —
CupixAuth::handleError | Undefined response: ... "Lens covered video detected." ...warn 로그 (sqsMessageb8c093e5-b871-408a-a749-54cd0612bc47) - 2026-06-25 05:30:21 KST —
BaseService::handlingMessageErrors | Error and message object - {"error":"undefined response", ...}error 로그 (cluster first_seen) - 2026-06-25 06:19:08 KST — 동일 패턴 warn 로그 (sqsMessage
31e700b7-08e1-4533-b7cb-945fd37ae748) - 2026-06-25 06:19:09 KST — 동일 패턴 error 로그 (cluster last_seen)
- 2026-06-25 06:27:17–18 KST — 동일 패턴 한 차례 더 (sqsMessage
fabaeded-ba68-45cc-a2cc-0ccd47a129de); cluster 집계는 2건이지만 패턴은 지속됨
Error Log#
BaseService::handlingMessageErrors | Error and message object - {"error":"undefined response","sqsMessage":{"MessageId":"b8c093e5-b871-408a-a749-54cd0612bc47","Attributes":{"ApproximateReceiveCount":"1"}}}
Impact#
- Service:
cupixworks-capture-preprocessor-agent - Team: mortenson
- 발생 횟수: 2
- 최초 발생: 2026-06-25 05:30 KST
- 최근 발생: 2026-06-25 06:19 KST
운영 영향은 낮다. SQS 메시지는 getApiErrorToDeleteMessage 가 'undefined response' (truthy 문자열)을 반환하므로 정상적으로 삭제되고, capture 의 error state 도 갱신된다. 그러나 에러 로그가 도메인 실패(렌즈가 가려진 비디오)를 외부 응답 누락처럼 표현해 운영자/온콜이 잘못된 트리아지를 할 위험이 있다.
Root Cause Summary#
PreprocessorService.checkSupportedVideo 가 비디오 검증 실패 시 HTTP response 가 아닌 plain new Error(result.reason) 을 throw 하는데, BaseService.getApiErrorToDeleteMessage 와 CupixAuth.handleError 모두 error.response 가 있는 HTTP 에러를 가정하고 작성되었다. 두 함수 모두 response == undefined 분기에서 'undefined response' 라는 문자열만 남기기 때문에, 실제 원인인 Lens covered video detected. 메시지가 BaseService 의 최종 error 로그에서 사라진다. 즉, 도메인 검증 실패와 HTTP 응답 누락이 같은 코드 경로로 합쳐져 있는 분류 누락이 root cause 다.
Technical Analysis#
Code Path#
- Entry point:
packages/base/src/base-service.ts:108—runByMessages()try/catch - Failure throw:
packages/cupix-capture-preprocessor-agent/src/preprocessor-service.ts:865—throw new Error(result.reason) - API-layer warn:
packages/api/src/authentication/cupix-auth.ts:54—CupixAuth::handleError | Undefined response - Final error log:
packages/base/src/base-service.ts:311—BaseService::handlingMessageErrors | Error and message object - Misclassification:
packages/base/src/base-service.ts:249-253—error.response미존재 시'undefined response'문자열 반환
검증 실패는 자식 프로세스가 쓴 valid.json 의 status_code 가 0 보다 클 때 발생한다:
const result = CPUtils.isJsonString(_data) ? JSON.parse(_data) : undefined;
if (result.status_code > 0) {
const _errorCode = ErrorCode.Scenemapper.statusCode(result.status_code.toString());
this.jobManager.setErrorCode(_errorCode);
logger.error('PreprocessorService::checkSupportedVideo | end - found unsupported video - %s', _errorCode);
throw new Error(result.reason);
}
여기서 throw 되는 객체는 plain Error 이므로 .response, .errno, .code, .syscall 모두 없다. 호출 경로 어디선가 CupixAuth.handleError 를 통과하면 다음 분기를 탄다:
handleError = (ec: any): any => {
const response = ec && CPUtils.isJsonString(ec) ? JSON.parse(ec) : ec.response;
if (response != undefined) {
// ... HTTP 분기 (statusCode/uri/body)
} else {
logger.warn('CupixAuth::handleError | Undefined response: %s', JSON.stringify(ec, Object.getOwnPropertyNames(ec)));
}
return ec;
};
→ CupixAuth::handleError | Undefined response: {"stack":"...","message":"Lens covered video detected."} warn 로그가 남는다. 이 부분이 Datadog 로그에서 동일 시각에 페어로 관측된다.
마지막으로 BaseService 에서:
private getApiErrorToDeleteMessage = (error: any): any => {
if (error == undefined) { /* ... */ return 'undefined error'; }
if (error.errno != undefined && error.code != undefined && error.syscall != undefined) { /* ... */ return; }
const response = CPUtils.isJsonString(error) ? JSON.parse(error) : error.response;
if (response == undefined) {
logger.warn('BaseService::getApiErrorToDeleteMessage | undefined response', error);
return 'undefined response';
}
// ...
};
error.response 는 undefined 이므로 'undefined response' 문자열을 반환. 이 값이 그대로 errorAndMessage.error 에 들어가 최종 로그에 노출된다:
private handlingMessageErrors = async (error: any): Promise<void> => {
const errorAndMessage = { error: error, sqsMessage: {} };
if (this.messageInProcess) {
errorAndMessage.sqsMessage = { MessageId: ..., Attributes: ... };
const apiErrorObject = this.getApiErrorToDeleteMessage(error);
if (apiErrorObject != undefined || this.checkReceiveCountToDeleteMessage()) {
try {
errorAndMessage.error = apiErrorObject; // <-- 'undefined response' 문자열로 덮어씀
await this.deleteByMessage(this.messageInProcess);
if (this._modelInProcess != undefined && this._modelInProcess.id > 0) await this.updateErrorState(this._modelInProcess);
} catch (error) { /* ... */ }
}
}
logger.error('BaseService::handlingMessageErrors | Error and message object - %s', JSON.stringify(errorAndMessage));
resetLogMeta();
};
기대 동작: 도메인 검증 실패 시 result.reason ("Lens covered video detected.") 와 errorCode 가 로그에 남아야 한다. 실제 동작: 원본 메시지가 'undefined response' 문자열로 치환되어 도메인 정보가 사라진다.
Log Evidence#
Datadog 쿼리:
service:cupixworks-capture-preprocessor-agent "BaseService::handlingMessageErrors"
service:cupixworks-capture-preprocessor-agent "undefined response"
페어로 관측된 warn + error 로그 (2026-06-25 05:30 KST):
{
"timestamp": "2026-06-25 05:30:20",
"status": "warn",
"message": "CupixAuth::handleError | Undefined response: {\"stack\":\"Error: Lens covered video detected.\n at PreprocessorService.checkSupportedVideo (/tmp/agent/dist/app.cjs:9899:15)\n ...\n at async BaseService2.runByMessage (/tmp/agent/dist/app.cjs:6151:15)\n at async BaseService2.runByMessages (/tmp/agent/dist/app.cjs:6139:13)\n at async BaseService2.checkingQueue (/tmp/agent/dist/app.cjs:6103:15)\n ...\",\"message\":\"Lens covered video detected.\"}"
}
{
"timestamp": "2026-06-25 05:30:21",
"status": "error",
"message": "BaseService::handlingMessageErrors | Error and message object - {\"error\":\"undefined response\",\"sqsMessage\":{\"MessageId\":\"b8c093e5-b871-408a-a749-54cd0612bc47\",\"Attributes\":{\"ApproximateReceiveCount\":\"1\"}}}"
}
24시간 내 동일 서비스에서 "undefined response" 키워드는 12건 관측되었고, 이 중 BaseService::handlingMessageErrors 의 "error":"undefined response" 는 3건 (이번 cluster 의 2건 + 06:27:18 KST 1건). 나머지 9건은 CupixAuth::handleError | Undefined response: ... warn 로그로, "Lens covered video detected." (3건), ETIMEDOUT (2건), ECONNRESET (4건) 메시지를 포함한다. 즉 같은 코드 경로가 도메인 에러와 네트워크 에러를 동일하게 처리한다.
비교를 위해, 같은 BaseService 로그 11건 중 9건은 error.response 가 채워진 정상 분기 — statusCode:403 + bodyResult:{"code":"ENT4000","reason":"Capture not found"} 형태로 풍부한 컨텍스트를 남긴다 (2026-06-24 19:47, 19:16, 18:57, 18:46, 16:00 등 다수). 즉 HTTP 분기는 잘 동작하고, plain Error 분기만 정보가 유실된다.
Hypotheses Considered#
| # | Hypothesis | Evidence for | Evidence against | Verdict |
|---|---|---|---|---|
| H1 | checkSupportedVideo 의 throw new Error(result.reason) 가 getApiErrorToDeleteMessage / CupixAuth.handleError 의 HTTP-response 가정과 어긋나 도메인 컨텍스트가 'undefined response' 문자열로 평탄화된다 |
preprocessor-service.ts:865 의 plain Error throw, base-service.ts:249-253 의 fallback, 같은 시각 페어로 찍힌 warn(Lens covered video detected.) + error("error":"undefined response") 로그 |
— | Confirmed |
| H2 | 외부 API (api-tesla.cupix.internal) 가 빈 응답을 돌려주어 발생 |
같은 서비스에서 ETIMEDOUT/ECONNRESET 워닝도 보임 (22:08–22:48 KST) |
이번 cluster 의 두 건은 stack trace 가 정확히 PreprocessorService.checkSupportedVideo 에서 시작하며 HTTP request 호출 흔적이 없음. CupixAuth::handleError 에 들어온 객체에도 statusCode/uri 가 없고 message 만 Lens covered video detected. 로 찍힘 |
Rejected |
| H3 | valid.json 파싱 실패로 result 가 undefined → result.status_code 접근 시 TypeError 가 throw 됨 |
preprocessor-service.ts:860 의 JSON.parse 실패 가능성 |
TypeError 라면 stack 첫 프레임이 JSON.parse 또는 checkSupportedVideo 의 line 861 이어야 하는데, 로그 stack 은 line 9899 (checkSupportedVideo) 의 throw new Error(result.reason) 와 일치하고 message 가 정확히 Lens covered video detected. 로 도메인 reason 문자열 |
Rejected |
| H4 | SQS poison message 로 메시지가 무한 retry 됨 | ApproximateReceiveCount:"1" 이라 retry 이력 없음. getApiErrorToDeleteMessage 가 truthy('undefined response')를 반환하므로 deleteByMessage 가 호출되어 즉시 삭제 |
— | Rejected |
Fix Recommendation#
즉시 조치 (Critical)#
없음. 사용자 영향이 없는 로깅 분류 문제이며, 메시지/state 처리는 정상.
단기 개선 (1주 이내)#
packages/base/src/base-service.ts:240-253getApiErrorToDeleteMessage가error instanceof Error인 경우 (HTTP response 도 아니고 nodejs syscall 에러도 아닌 경우)에 대해 별도 분기를 두어error.message/error.name/ 가능하면jobManager.errorCode를 반환하도록 한다. 그래야errorAndMessage.error에Lens covered video detected.가 그대로 남는다.packages/api/src/authentication/cupix-auth.ts:42-56CupixAuth.handleError의 fallback 분기는 도메인 에러까지 잡고 있다. 호출처(예:transfer.manager.ts:73,78,83,102)에서 정말 HTTP response 인 경우에만handleError를 호출하도록 정리하거나, fallback 로그 레벨을 케이스별로 조정한다. 현재 동일 plain Error 가 두 군데에서 "Undefined response" 로 두 번 로깅된다.cupix-capture-preprocessor-agent의 도메인 검증 실패는error가 아닌warn(또는 별도 도메인 에러 클래스) 로 분류해 운영 알림 노이즈를 줄인다. 메모리 노트(AUTH20022/AUTH20023 episode) 와 같은 맥락 — "expected operational scenario" 는 error 가 아니어야 한다.
장기 개선 (재발 방지)#
- agents 공통 base 에 도메인 에러 / HTTP 에러 / 시스템 에러를 구분하는 타입 계층을 도입 (
DomainValidationError,UpstreamHttpError,SystemError). 현재any로 받는 패턴이 분류 누락을 만든다. valid.json의status_code매핑을ErrorCode.Scenemapper처럼 코드/메시지 모두 갖춘 enum 으로 throw 해, 로그에서 errorCode 가 자동으로 노출되도록 한다.
Monitoring#
error: "undefined response" 패턴 자체가 분류 누락의 카나리이므로 agents 전체에서 추적한다.
service:cupixworks-capture-preprocessor-agent status:error "BaseService::handlingMessageErrors" "undefined response"
service:(cupixworks-capture-preprocessor-agent OR cupixworks-capture-postprocessor-agent OR cupixworks-tesla-forge-agent) "CupixAuth::handleError" "Undefined response"
service:cupixworks-capture-preprocessor-agent "Lens covered video detected"
세 쿼리는 Datadog timeseries widget 에서 그대로 그래프로 렌더 가능하다 (monitor-only 문법 사용 안 함). 첫 쿼리가 0 으로 떨어지면 분류 패치가 반영된 것이다.
Risk Assessment#
- Risk level: low — 사용자 영향 없음, 메시지 처리 정상, 로그 가독성/트리아지 정확도 문제만 존재
- 예상 복잡도: standard — base-service / cupix-auth 두 곳의 분기를 손봐야 하고, agents 다수 패키지에서 동일 패턴이 사용 중이라 회귀 테스트 필요