ES /docs

ForgeAgent off-by-one error accessing invalid object ID in SVF2

RCA: ForgeAgents - Error: { code: 1, message: Failed to get properties and children }

Error Log#

Datadog Logs

text
ForgeAgents - Error: { code: 1, message: Failed to get properties and children }

Impact#

  • Service: cupixworks-any-room-agent
  • 발생 횟수: 1
  • 최초 발생: 2026-04-09T06:44:25.133Z
  • 최근 발생: 2026-04-09T06:44:25.133Z

Root Cause Summary#

BIM ID 18949의 SVF2 모델 property database를 순회하는 과정에서 @cupix/forge-agents 라이브러리가 유효하지 않은 object ID 759923에 접근을 시도했습니다 (유효 범위: 1~759922). 이 off-by-one 에러는 라이브러리 내부에서 발생하며, RoomExtractorProcess.execute()에서 ForgeAgent.extract() 호출 결과의 result.Error 값이 ForgeAgentErrorCode.FORGE_SOURCE_INVALID_MANIFEST가 아닌 다른 에러 코드(code: 1)로 반환되었기 때문에 SVF1 fallback 없이 "Failed to get rooms from svf2" 예외가 throw되었습니다. 이 에러는 해당 BIM 모델 파일의 property database가 손상되었거나, 노드 참조가 실제 데이터 범위를 초과하는 경우에 발생합니다.

Technical Analysis#

Code Path#

  • Entry point: BaseService.checkingQueue() — SQS 메시지 수신 후 runByMessages() 호출 (base-service.ts:107-108)
  • BaseService.runByMessage() — 메시지 파싱 후 this.run(targetId) 호출 (base-service.ts:170)
  • RoomService.run() — BIM 객체 생성 후 runRoomExtractor(cpBim) 호출 (room-service.ts:68)
  • RoomService.runRoomExtractor()RoomExtractManager.execute() 호출 (room-service.ts:187)
  • RoomExtractManager.execute() — child process로 IPC 메시지 전달 (room-extract.manager.ts:29)
  • RoomExtractorProcess.execute()ForgeAgent.extract() 호출, 결과의 Error 필드 검사 (room-extractor.process.ts:40-53)
  • Failure point: room-extractor.process.ts:52result.ErrorFORGE_SOURCE_INVALID_MANIFEST가 아니므로 catch-all throw 실행
typescript
// 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(){ code: 1, message: "Failed to get properties and children" } 에러를 반환했으나, 이 에러 코드는 FORGE_SOURCE_INVALID_MANIFEST와 일치하지 않습니다. 현재 코드는 manifest invalid 에러만 SVF1 fallback으로 처리하고, 그 외 모든 에러는 동일하게 throw합니다.

에러 전파 경로:

typescript
// packages/base/src/manager/child-process.manager.ts:179-183
if (response.success) {
    pending.resolve(response.data);
} else {
    pending.reject(new Error(response.error || 'Unknown error'));  // IPC 에러 전파
}
typescript
// packages/base/src/base-service.ts:107-111
try {
    await this.runByMessages();
} catch (error) {
    await this.handlingMessageErrors(error);  // 최종 에러 핸들링
}
typescript
// packages/base/src/base-service.ts:290-313
private handlingMessageErrors = async (error: any): Promise<void> => {
    const errorAndMessage = { error: error, sqsMessage: {} };
    if (this.messageInProcess) {
        // ...
        const apiErrorObject = this.getApiErrorToDeleteMessage(error);
        if (apiErrorObject != undefined || this.checkReceiveCountToDeleteMessage()) {
            await this.deleteByMessage(this.messageInProcess);
            if (this._modelInProcess != undefined) await this.updateErrorState(this._modelInProcess);
        }
    }
    logger.error('BaseService::handlingMessageErrors | Error and message object - %s', JSON.stringify(errorAndMessage));
};

getApiErrorToDeleteMessage()에서 Error 객체는 response 프로퍼티가 없으므로 "undefined response"를 반환합니다. 이 값이 truthy이므로 SQS 메시지가 삭제되고 BIM 상태가 Error로 업데이트됩니다.

Log Evidence#

사용한 Datadog 쿼리:

text
service:cupixworks-any-room-agent "Failed to get properties and children" status:error
text
service:cupixworks-any-room-agent

에러 cascade (5개 로그, 동일 밀리초 내 발생):

text
2026-04-09T06:44:25.132Z | ERROR | Failed to get properties and children: Invalid object ID: 759923. Valid range is 1 to 759922.
2026-04-09T06:44:25.132Z | ERROR | Failed to get node: Failed to get properties and children
2026-04-09T06:44:25.132Z | ERROR | Failed to traverse nodes: Failed to get properties and children
2026-04-09T06:44:25.133Z | ERROR | Failed to use property database: Failed to get properties and children
2026-04-09T06:44:25.133Z | ERROR | ForgeAgents - Error: { code: 1, message: Failed to get properties and children }

이후 에러 전파 로그:

text
2026-04-09T06:44:25.136Z | ERROR | Failed to get rooms from svf2 (bim.id: 18949, stack: Error at ChildProcessManager2.handleMessage /tmp/agent/dist/app.cjs:5213:26)
2026-04-09T06:44:25.138Z | WARN  | Failed to get rooms from svf2 (bim.id: 18949)

SQS 메시지 삭제 및 최종 에러 핸들링:

text
2026-04-09T06:44:25.138Z | INFO  | AwsQueueManager::deleteMessage | begin - queue: cupix-tesla-room-agent-production
2026-04-09T06:44:25.168Z | INFO  | AwsQueueManager::deleteMessage | end - message id: 1cc77d38-fb8b-4272-bbf9-13fe1fedeb7b
json
{
  "message": "BaseService::handlingMessageErrors | Error and message object",
  "error": "undefined response",
  "sqsMessage": {
    "MessageId": "1cc77d38-fb8b-4272-bbf9-13fe1fedeb7b",
    "Attributes": { "ApproximateReceiveCount": "1" }
  }
}

영향받은 엔티티:

14일간 ForgeAgents 에러 현황: code: 1 (property database 에러)은 이번 1건이 유일합니다. 가장 빈번한 에러는 code: 305 (geometry 로드 실패)와 INVALID_OTG_ERROR (OTG pending 상태)입니다.

Fix Recommendation#

즉시 조치 (Critical)#

  • 파일: packages/cupix-tesla-room-agent/src/process/room-extractor.process.ts:46-53
  • result.Error 처리 로직에서 property database 관련 에러(code: 1)도 SVF1 fallback 대상에 포함시키는 것을 검토해야 합니다. 현재는 FORGE_SOURCE_INVALID_MANIFEST만 fallback 처리하고 그 외 에러는 모두 실패로 처리합니다. property database 순회 실패는 SVF2 파일 자체의 문제일 가능성이 높으므로, SVF1으로 재시도하면 성공할 수 있습니다.
  • 에러 throw 시 원본 result.Error 정보(code, message)를 포함하도록 에러 메시지를 개선하면 디버깅이 용이해집니다.

단기 개선 (1주 이내)#

  • SVF1 fallback 대상 에러 코드를 화이트리스트가 아닌 블랙리스트 방식으로 전환하는 것을 검토합니다. 즉, fallback이 불가능한 에러만 명시적으로 제외하고, 나머지 에러는 모두 SVF1 fallback을 시도하도록 합니다.
  • bim-revision-agentForgeErrorMapper 패턴을 참고하여, room-agent에서도 에러 코드별 처리 전략을 체계화합니다.

장기 개선 (재발 방지)#

  • @cupix/forge-agents 라이브러리 내부에서 property database 순회 시 object ID 범위 검증을 강화하여, off-by-one 에러가 발생하지 않도록 합니다.
  • SVF2 모델 파일의 무결성 검증 단계를 extraction 전에 추가하여, 손상된 모델에 대해 조기 감지 및 적절한 에러 코드 반환이 가능하도록 합니다.

Monitoring#

  • 추가할 메트릭: ForgeAgents 에러를 error code별로 분류하여 추적
  • Datadog 쿼리 예시:
text
service:cupixworks-any-room-agent "ForgeAgents - Error" status:error @environment:production
text
service:cupixworks-any-room-agent "Failed to get rooms from svf2" status:error @environment:production

Risk Assessment#

  • Risk level: low
  • 예상 복잡도: standard
  • 14일간 동일 에러 코드(code: 1) 발생은 이번 1건이 유일하며, 특정 BIM 모델(ID 18949)의 property database 문제로 한정됩니다. 사용자 영향은 해당 BIM의 room extraction 실패로 제한되며, 에러 발생 후 BIM 상태가 Error로 업데이트되고 다음 메시지 처리는 정상 진행되었습니다.