ES /docs

Failed to use geometries: Failed to load geometries for 99d37c96-d1f6-e2c4-b000-0014b473df40

RCA: Failed to use geometries: Failed to load geometries for 99d37c96-d1f6-e2c4-b000-0014b473df40

Error Log#

Datadog Logs

text
Failed to use geometries: Failed to load geometries for 99d37c96-d1f6-e2c4-b000-0014b473df40

Impact#

  • Service: cupixworks-any-room-agent
  • 발생 횟수: 1
  • 최초 발생: 2026-04-08T10:43:27.462Z
  • 최근 발생: 2026-04-08T10:43:27.462Z
  • 영향 범위: BIM ID 134, team qatest (id: 3), user ginny.choi@cupix.com (id: 572). 해당 BIM의 room extraction 작업이 실패하여 room 정보가 추출되지 않았으며, BIM의 room_state가 Error로 전환되었을 가능성이 있음.

Root Cause Summary#

@cupix/forge-agents 라이브러리가 Autodesk Forge API를 통해 SVF2 포맷의 BIM 모델에서 geometry를 로드하는 과정에서 실패했습니다. ForgeAgent.extract() 호출 결과에 error code 305가 반환되었고, 이 코드는 FORGE_SOURCE_INVALID_MANIFEST(코드값이 다름)도 아닌 알 수 없는 geometry 로딩 실패 코드입니다. RoomExtractorProcess의 error handling 로직에서 FORGE_SOURCE_INVALID_MANIFEST가 아닌 모든 에러에 대해 SVF1 fallback 없이 즉시 "Failed to get rooms from svf2" 에러를 throw하며, 이 에러가 child process를 통해 전파되어 SQS 메시지가 첫 번째 시도에서 삭제되었습니다. geometry ID 99d37c96-d1f6-e2c4-b000-0014b473df40에 대한 Forge API 응답 실패가 근본 원인이며, 이는 해당 BIM 모델의 Forge 변환 상태 이상이나 Forge API 일시 장애로 추정됩니다.

Technical Analysis#

Code Path#

  1. Entry point: SQS 메시지 수신 및 RoomService.run() 호출
typescript
// applications/agents/packages/cupix-tesla-room-agent/src/room-service.ts:58-68
protected run = async (targetId: number): Promise<void> => {
    const cpBim = await this.createCPBimByBimId(targetId);
    if (cpBim) {
        this._modelInProcess = cpBim;
        this._forgeApi.updateRegionFromBim(cpBim.forgeRegion);
        if (cpBim.workspaceDirPath) this.setModelWorkspace(cpBim.workspaceDirPath);

        if (cpBim.isGenerateMasterViews) {
            await this.forgeAuth.authenticate();
            await this.updateBimRoomState(targetId, TESLA.UpdateBimRequest.RoomStateEnum.Extracting);
            await this.runRoomExtractor(cpBim);  // <-- 여기서 호출
  1. Room extraction 위임: RoomExtractManager가 child process를 통해 RoomExtractorProcess를 실행
typescript
// applications/agents/packages/cupix-tesla-room-agent/src/manager/room-extract.manager.ts:25-42
async execute(params: RoomExtractorParams): Promise<RoomExtractorResults> {
    try {
        const result = await this.childProcessManager.execute<RoomExtractorResults>('execute', params);
        return result;
    } catch (error) {
        const errorCode = ErrorCode.Agent.RoomExtractorExecute;
        if (this.setJobErrorCode) {
            this.setJobErrorCode(errorCode);
        }
        throw error;
    }
}
  1. Failure point: RoomExtractorProcess에서 ForgeAgent.extract() 호출 후 에러 분기
typescript
// applications/agents/packages/cupix-tesla-room-agent/src/process/room-extractor.process.ts:39-53
if (params.formatType === 'svf2') {
    const result = await ForgeAgent.extract(params.apiConfig, params.urn, {
        extractRoom: true,
        extractMeta: true,
        region: params.region
    });

    if (result.Error == undefined) {
        extract = result;
    } else if (result.Error === ForgeAgentErrorCode.FORGE_SOURCE_INVALID_MANIFEST) {
        this.log('RoomExtractorProcess::execute - svf2 manifest is invalid, try svf1 process');
        extract = await RoomExtractor.room_extract(params.token, params.urn);
    } else {
        throw new Error('Failed to get rooms from svf2');  // <-- 여기서 throw
    }
}

ForgeAgent.extract()result.Error = 305를 반환했으나, 이 값은 FORGE_SOURCE_INVALID_MANIFEST와 일치하지 않으므로 else 분기로 진입하여 에러가 throw됩니다. 에러 코드 305는 @cupix/forge-agents 라이브러리 내부에서 geometry 로딩 실패 시 반환하는 코드로, "Failed to load geometries for {id}" 메시지와 함께 기록됩니다.

  1. SQS 메시지 삭제 흐름: 에러가 BaseService.handlingMessageErrors()까지 전파
typescript
// applications/agents/packages/base/src/base-service.ts:240-252
private getApiErrorToDeleteMessage = (error: any): any => {
    if (error == undefined) {
        return 'undefined error';
    }
    if (error.errno != undefined && error.code != undefined && error.syscall != undefined) {
        return;  // system error는 undefined 반환 → 재시도 가능
    }
    const response = CPUtils.isJsonString(error) ? JSON.parse(error) : error.response;
    if (response == undefined) {
        return 'undefined response';  // <-- Error 객체는 여기에 해당
    }
    // ...
};

throw new Error('Failed to get rooms from svf2')로 생성된 Error 객체는 errno/code/syscall 속성이 없고, error.response도 undefined이므로 'undefined response'(truthy)를 반환합니다.

typescript
// applications/agents/packages/base/src/base-service.ts:300-305
const apiErrorObject = this.getApiErrorToDeleteMessage(error);
if (apiErrorObject != undefined || this.checkReceiveCountToDeleteMessage()) {
    errorAndMessage.error = apiErrorObject;
    await this.deleteByMessage(this.messageInProcess);  // <-- 첫 시도에서 삭제
    if (this._modelInProcess != undefined && this._modelInProcess.id > 0)
        await this.updateErrorState(this._modelInProcess);
}

apiErrorObject'undefined response'(truthy)이므로 checkReceiveCountToDeleteMessage()의 결과와 관계없이 메시지가 삭제됩니다. ApproximateReceiveCount: "1"이 이를 확인합니다.

Log Evidence#

Datadog 로그 검색에서 해당 시간대 전후로 7개의 관련 로그를 확인했습니다.

검색 쿼리:

text
service:cupixworks-any-room-agent status:error @environment:production "Failed to load geometries"
text
service:cupixworks-any-room-agent @environment:production 99d37c96-d1f6-e2c4-b000-0014b473df40
text
service:cupixworks-any-room-agent @environment:production (from:2026-04-08T10:40:00Z to:2026-04-08T10:46:00Z)

에러 캐스케이드 타임라인:

시간 (UTC) Level 메시지 비고
10:43:27.462Z error Failed to use geometries: Failed to load geometries for 99d37c96-d1f6-e2c4-b000-0014b473df40 @cupix/forge-agents 라이브러리 로그
10:43:27.463Z error ForgeAgents - Error: { code: 305, message: Failed to load geometries for 99d37c96-d1f6-e2c4-b000-0014b473df40 } error code 305 확인
10:43:27.467Z error Failed to get rooms from svf2 room-extractor.process.ts:52 throw
10:43:27.469Z warn Failed to get rooms from svf2 동일 에러 warn 레벨 중복 기록
10:43:27.469Z info AwsQueueManager::deleteMessage | begin SQS 메시지 삭제 시작
10:43:27.499Z info AwsQueueManager::deleteMessage | end - message id: ccd05145-cf56-4373-a5cc-29f49bb67d2e 삭제 완료
10:43:27.692Z error BaseService::handlingMessageErrors | Error and message object - {"error":"undefined response","sqsMessage":{"MessageId":"ccd05145-...","Attributes":{"ApproximateReceiveCount":"1"}}} 최종 에러 기록

핵심 로그 원문:

json
{
  "error": "undefined response",
  "sqsMessage": {
    "MessageId": "ccd05145-cf56-4373-a5cc-29f49bb67d2e",
    "Attributes": {
      "ApproximateReceiveCount": "1"
    }
  }
}

관찰 사항:

  • 에러 발생 시점(10:43:27.462Z)부터 SQS 메시지 삭제 완료(10:43:27.499Z)까지 약 37ms
  • geometry ID 99d37c96-d1f6-e2c4-b000-0014b473df40를 참조하는 다른 서비스의 로그는 없음 — 에러가 any-room-agent 내부에 격리됨
  • ApproximateReceiveCount: "1" — 첫 번째 수신에서 메시지가 삭제되어 재시도 불가
  • session/user 정보는 에러 #3 이후에만 로그에 포함됨 (session: be13eccc..., BIM ID: 134, team: qatest)
  • host: ip-10-1-37-178.ap-southeast-1.compute.internal (ap-southeast-1 리전)

Fix Recommendation#

즉시 조치 (Critical)#

room-extractor.process.ts:51-52에서 error code 305를 포함한 geometry 로딩 실패 시, 에러 코드를 에러 메시지에 포함시켜야 합니다. 현재 throw new Error('Failed to get rooms from svf2')는 원래의 result.Error 코드를 소실시키고 있어 디버깅이 어렵습니다. 에러 메시지에 result.Error 코드와 원본 메시지를 포함하도록 수정이 필요합니다.

단기 개선 (1주 이내)#

  1. SVF1 fallback 확대 검토: 현재 FORGE_SOURCE_INVALID_MANIFEST 에러에 대해서만 SVF1 fallback이 작동합니다(room-extractor.process.ts:48-50). error code 305(geometry 로딩 실패)와 같은 다른 Forge 에러에 대해서도 SVF1 fallback을 적용할 수 있는지 검토가 필요합니다.

  2. SQS 메시지 삭제 로직 검토: getApiErrorToDeleteMessage() (base-service.ts:240-276)에서 일반 Error 객체(response 속성 없음)가 'undefined response'를 반환하여 메시지가 첫 시도에서 삭제되는 동작은 의도된 것인지 확인이 필요합니다. Forge API의 일시적 장애인 경우 재시도로 복구될 수 있으나, 현재 로직에서는 재시도 기회가 없습니다.

장기 개선 (재발 방지)#

  1. Forge 에러 코드별 처리 전략: RoomExtractorProcess에서 ForgeAgentErrorCode의 각 에러 코드별로 적절한 처리 방향(fallback, 재시도, 에러 종료)을 정의하는 매핑이 필요합니다. bim-revision-agentForgeErrorMapper 패턴을 room-agent에도 적용하는 것을 고려할 수 있습니다.

  2. Transient error에 대한 재시도 메커니즘: Forge API 호출 실패가 일시적인 경우를 구분하여, SQS visibility timeout을 활용한 자동 재시도가 가능하도록 에러 분류 체계를 개선해야 합니다.

Monitoring#

  • Forge geometry 로딩 실패를 추적하는 메트릭 추가:
text
service:cupixworks-any-room-agent status:error "ForgeAgents - Error" @environment:production
  • Error code 305 발생 빈도 모니터링:
text
service:cupixworks-any-room-agent "code: 305" @environment:production
  • Room agent의 SQS 메시지 삭제 후 error state 전환 비율:
text
service:cupixworks-any-room-agent "handlingMessageErrors" "undefined response" @environment:production

Risk Assessment#

  • Risk level: low
  • 예상 복잡도: standard
  • 근거: 단일 발생(1회) 이벤트이며, qatest team에서 발생하여 production 사용자 영향은 제한적입니다. 그러나 동일한 에러 패턴이 production team에서 발생할 경우, room extraction 실패 후 재시도 없이 메시지가 소실되므로 BIM 처리 파이프라인이 stuck 상태에 빠질 수 있습니다.