ES /docs

ForgeAgent extract — out-of-bounds object ID reference in SVF2

RCA: Failed to traverse nodes: Failed to get properties and children

Overview#

What Happened#

2026-04-23 19:46 UTC에 cupixworks-any-room-agent 서비스에서 BIM ID 19176 (팀 benchmarkgc, 사용자 csollenberger@benchmarkgc.com)의 room extraction 처리 중 Autodesk Forge SVF2 property database 순회 과정에서 유효하지 않은 object ID 참조 에러가 발생했다. @cupix/forge-agents 라이브러리가 object ID 9217을 조회했으나, 해당 모델의 유효 범위가 1~9216이어서 property database 접근이 실패하고, 에러가 child process에서 parent process로 전파되며 최종적으로 SQS 메시지 삭제 및 BIM room_state를 Error로 전환하며 종료되었다.

Quick Facts#

Field Value
exception.message Failed to traverse nodes: Failed to get properties and children
top_frame @cupix/forge-agents (external library — property database traversal)
env production, us-west-2
BIM ID 19176
SQS Message ID 23bb29ea-16f7-4adf-bbb2-8d3b38a34d42
SQS Queue cupix-tesla-room-agent-production

Affected Teams#

Team / Domain Error Count Impact
benchmarkgc (ID 1216) 1 BIM room extraction 실패 — room_state가 Error로 전환되어 해당 BIM 모델의 room 데이터 사용 불가

Timeline#

  1. 19:46:13.987Z — SQS 메시지 수신, BIM ID 19176 처리 시작 (BaseService::runByMessage)
  2. 19:46:14.028Z — Cupix 인증 세션 설정 (session_id: 01f25334a39bd45ae...)
  3. 19:46:15.015ZRoomExtractManager::execute 시작, Forge URN으로 SVF2 extraction 호출
  4. 19:46:18.200Z@cupix/forge-agents에서 root cause 에러 발생: Invalid object ID: 9217. Valid range is 1 to 9216.
  5. 19:46:18.201Z — 에러 체인 전파 (get node → use property database → traverse nodes → ForgeAgents Error)
  6. 19:46:18.203ZBaseService::handlingMessageErrors에서 SQS 메시지 삭제 및 BIM Error state 업데이트
  7. 19:46:18.239Z — SQS 메시지 삭제 완료

Error Log#

Datadog Logs

text
Failed to traverse nodes: Failed to get properties and children

Impact#

  • Service: cupixworks-any-room-agent
  • 발생 횟수: 1
  • 최초 발생: 2026-04-23T19:46:18.201Z
  • 최근 발생: 2026-04-23T19:46:18.201Z

Root Cause Summary#

BIM ID 19176의 RVT 파일(19176_1776972884833_HLC_HB.rvt)을 Autodesk Forge SVF2 포맷으로 변환 후 room extraction을 수행하는 과정에서, @cupix/forge-agents 라이브러리가 property database를 순회할 때 object ID 9217을 참조했으나, 해당 모델의 유효 object ID 범위가 1~9216이었다. 이는 Forge 서버 측 model derivative 변환 결과에 경계 바깥의 object reference가 포함되었거나, RVT 원본 파일에 corrupt된 element가 존재하기 때문이다. ForgeAgent.extract()result.Error를 설정하여 반환했고, 이 에러 코드가 FORGE_SOURCE_INVALID_MANIFEST가 아니어서 SVF1 fallback이 트리거되지 않았고, "Failed to get rooms from svf2" 예외가 throw되었다. 에러는 child process → manager → service → BaseService로 전파되어 최종적으로 BIM의 room_state를 Error로 전환했다.

Technical Analysis#

Code Path#

  • Entry point: room-service.ts:58run() 메서드에서 BIM 처리 시작
  • room-service.ts:66-68 — Forge 인증 후 runRoomExtractor(cpBim) 호출
packages/cupix-tesla-room-agent/src/room-service.ts:65-68typescript
if (cpBim.isGenerateMasterViews) {
    await this.forgeAuth.authenticate();
    await this.updateBimRoomState(targetId, TESLA.UpdateBimRequest.RoomStateEnum.Extracting);
    await this.runRoomExtractor(cpBim);
  • room-service.ts:187RoomExtractManager.execute()에 Forge API config, URN, format type 전달
packages/cupix-tesla-room-agent/src/room-service.ts:187-195typescript
const roomExtractorResults = await this.roomExtractManager.execute({
    apiConfig: {
        clientId: Environment.ADF_CLIENT_ID,
        clientSecret: Environment.ADF_CLIENT_SECRET,
    },
    urn: cpBim.forgeUrn,
    formatType: cpBim.forgeFormatType,
    region: cpBim.forgeRegion
});
  • room-extract.manager.ts:29ChildProcessManager.execute()로 child process에서 실행
packages/cupix-tesla-room-agent/src/manager/room-extract.manager.ts:28-41typescript
try {
    const result = await this.childProcessManager.execute<RoomExtractorResults>('execute', params);
    logger.debug('RoomExtractManager::execute | completed successfully');
    return result;
} catch (error) {
    logger.error('RoomExtractManager::execute | error:', error);

    const errorCode = ErrorCode.Agent.RoomExtractorExecute;

    if (this.setJobErrorCode) {
        this.setJobErrorCode(errorCode);
    }

    throw error;
}
  • Failure point: room-extractor.process.ts:40-52ForgeAgent.extract() 호출 후 result.Error 확인
packages/cupix-tesla-room-agent/src/process/room-extractor.process.ts:39-53typescript
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');
    }

ForgeAgent.extract()는 내부적으로 property database를 순회하면서 object ID 9217을 참조했다. 해당 모델의 유효 범위(1~9216)를 벗어나서 "Invalid object ID" 에러가 발생했고, 이 에러는 result.Error에 에러 코드로 설정되어 반환되었다. 이 에러 코드가 FORGE_SOURCE_INVALID_MANIFEST와 다르기 때문에 SVF1 fallback 분기(line 48-50)로 진입하지 못하고, line 52에서 throw new Error('Failed to get rooms from svf2')가 실행되었다.

  • room-extractor.process.ts:66-75 — catch 블록에서 에러 로깅 후 re-throw
packages/cupix-tesla-room-agent/src/process/room-extractor.process.ts:66-76typescript
} catch (error) {
    const errorMessage = error instanceof Error ? error.message : String(error);
    const errorStack = error instanceof Error ? error.stack : undefined;

    this.log(`RoomExtractorProcess::execute | error: ${errorMessage}`);
    if (errorStack) {
        this.log(`RoomExtractorProcess::execute | stack: ${errorStack}`);
    }

    throw error;
}
  • Error propagation to BaseService: base-service.ts:108-110에서 최종 catch
packages/base/src/base-service.ts:106-111typescript
this._countWaitedToStopTask = 0;
try {
    await this.runByMessages();
} catch (error) {
    await this.handlingMessageErrors(error);
}
  • base-service.ts:290-311handlingMessageErrors()에서 에러 분류 및 SQS 메시지 삭제
packages/base/src/base-service.ts:240-243typescript
private getApiErrorToDeleteMessage = (error: any): any => {
    if (error == undefined) {
        logger.warn('BaseService::getApiErrorToDeleteMessage | undefined error');
        return 'undefined error';
    }

로그에서 "BaseService::getApiErrorToDeleteMessage | undefined error"가 출력된 것으로 보아, child process에서 parent process로 전파되는 과정에서 Error 객체가 직렬화에 실패하여 undefined로 수신된 것으로 추정된다. getApiErrorToDeleteMessage'undefined error' 문자열을 반환하면서 apiErrorObject != undefined 조건이 충족되어, SQS 메시지 삭제 및 updateErrorState() (room_state → Error)가 실행되었다.

Log Evidence#

Datadog에서 사용한 쿼리:

text
service:cupixworks-any-room-agent status:error @environment:production
text
service:cupixworks-any-room-agent @environment:production

에러 발생 전 정상 처리 로그 (info):

json
{"timestamp": "19:46:13.987Z", "level": "info", "message": "BaseService::runByMessage | id: 19176"}
json
{"timestamp": "19:46:14.028Z", "level": "info", "message": "CupixAuth::setSession | session_id: 01f25334a39bd45ae0a78c996f2b0c743fa71c06"}
json
{"timestamp": "19:46:15.015Z", "level": "info", "message": "RoomExtractManager::execute | urn: dXJuOmFkc2sub2JqZWN0czpvcy5vYmplY3Q6dGVzbGEtcHJvZHVjdGlvbi8xOTE3Nl8xNzc2OTcyODg0ODMzX0hMQ19IQi5ydnQ="}

에러 체인 (error level, 19:46:18.200~18.201Z):

text
Failed to get properties and children: Invalid object ID: 9217. Valid range is 1 to 9216.
text
Failed to get node: Failed to get properties and children
text
Failed to use property database: Failed to get properties and children
text
Failed to traverse nodes: Failed to get properties and children
text
ForgeAgents - Error: { code: 1, message: Failed to get properties and children }

에러 후 처리 로그 (warn + info):

text
BaseService::getApiErrorToDeleteMessage | undefined error
json
{"timestamp": "19:46:18.203Z", "level": "info", "message": "AwsQueueManager::deleteMessage | begin - queue url: https://sqs.us-west-2.amazonaws.com/002596530511/cupix-tesla-room-agent-production"}
json
{"timestamp": "19:46:18.239Z", "level": "info", "message": "AwsQueueManager::deleteMessage | end - message id: 23bb29ea-16f7-4adf-bbb2-8d3b38a34d42"}

최종 에러 로그:

json
{"timestamp": "19:46:18.495Z", "level": "error", "message": "BaseService::handlingMessageErrors | Error and message object - {\"error\":\"undefined error\",\"sqsMessage\":{\"MessageId\":\"23bb29ea-16f7-4adf-bbb2-8d3b38a34d42\",\"Attributes\":{\"ApproximateReceiveCount\":\"1\"}}}"}

동일 시간대에 다른 호스트(ip-10-1-37-252)에서는 다른 BIM 모델들이 정상 처리되고 있었으며, 이 에러는 BIM ID 19176에 국한된 단건 발생이었다.

Hypotheses Considered#

# Hypothesis Evidence for Evidence against Verdict
H1 BIM RVT 파일에 corrupt된 element가 있어 Forge SVF2 변환 시 유효 범위 밖의 object ID가 생성됨 로그에 Invalid object ID: 9217. Valid range is 1 to 9216. — 정확히 1개 초과된 ID. Forge property database가 off-by-one 또는 corrupt element 참조 다른 BIM 모델들은 동일 시간대에 정상 처리됨 (서비스 자체 문제 아님) Confirmed
H2 Forge API 서버 측 일시적 오류로 property database가 불완전하게 반환됨 object ID 범위 에러가 서버 측 데이터 문제일 수 있음 에러 메시지가 명확히 object ID 범위 검증 실패를 보여줌 — 일시적 오류라면 다른 유형의 에러(timeout, 500 등)가 나옴. 또한 단일 모델에서만 발생 Rejected
H3 @cupix/forge-agents 라이브러리의 SVF2 parser 버그로 잘못된 object ID를 생성 property database 순회 시 boundary check에서 실패한 점 에러 메시지 형태(Invalid object ID: 9217. Valid range is 1 to 9216)는 Forge SDK의 validation 로직에서 출력되는 것으로, 라이브러리가 아닌 데이터 문제를 가리킴. 다른 모델은 정상 Rejected
H4 SVF1 fallback이 트리거되었어야 하나 에러 코드 매핑 누락으로 fallback 실패 room-extractor.process.ts:48에서 FORGE_SOURCE_INVALID_MANIFEST만 fallback 조건으로 검사하며, property database 에러는 별도의 에러 코드를 가짐 SVF1 fallback은 manifest 자체가 invalid한 경우를 위한 것이며, property traversal 에러에 대해 SVF1도 동일한 결과를 낼 가능성이 높음 Inconclusive

Fix Recommendation#

즉시 조치 (Critical)#

  • 특별한 코드 수정 없음. 이 에러는 특정 BIM 파일(19176)의 데이터 문제로 인한 단건 발생이며, 서비스는 정상적으로 에러를 처리하고 room_state를 Error로 전환했다.
  • benchmarkgc 팀에게 해당 BIM 파일(HLC_HB.rvt)의 재업로드 또는 Autodesk에서 파일 검증을 권장할 수 있다.

단기 개선 (1주 이내)#

  • room-extractor.process.ts:52에서 throw하는 에러 메시지를 result.Error 코드를 포함하도록 개선: throw new Error(\Failed to get rooms from svf2: ${result.Error}`)` — 현재 generic한 메시지로는 실제 Forge 에러 코드를 파악하기 어렵다.
  • room-extractor.process.ts:48의 fallback 조건에 property database 관련 에러 코드를 추가하여, SVF2에서 실패 시 SVF1으로 재시도할지 검토. 단, SVF1에서도 동일한 결과가 나올 수 있으므로 실제 테스트 필요.

장기 개선 (재발 방지)#

  • @cupix/forge-agents 라이브러리에서 property database traversal 시 invalid object ID를 skip하고 나머지 유효한 room/level 데이터를 반환하는 graceful degradation 지원 검토.
  • child process → parent process 간 Error 객체 직렬화 문제 개선. 현재 child process에서 throw한 Error가 parent에서 undefined로 수신되어, BaseService::getApiErrorToDeleteMessage에서 "undefined error"로 기록됨. 에러 정보가 유실되면 디버깅이 어려워진다.

Monitoring#

  • Forge property database 에러에 대한 별도 모니터링:
text
service:cupixworks-any-room-agent status:error "Invalid object ID"
  • room extraction 에러율 추적 (BIM별):
text
service:cupixworks-any-room-agent status:error "Failed to get rooms from svf2"

Risk Assessment#

  • Risk level: low
  • 예상 복잡도: trivial
  • 단일 BIM 파일의 데이터 문제로 인한 단건 발생이며, 서비스 전체에 영향을 미치지 않는다. 동일 시간대에 다른 BIM 모델들은 정상 처리되었다.