@cupix/forge-agents SVF2 property DB boundary error
RCA: Failed to get node: Failed to get properties and children
Overview#
What Happened#
2026-04-23 19:46:18 UTC에 cupixworks-any-room-agent (실제 서비스명: cupix-tesla-room-agent) 서비스에서 BIM 모델(ID: 19176, 파일: HLC_HB.rvt)의 room extraction 처리 중 Autodesk Forge SVF2 property database 순회 과정에서 off-by-one 오류가 발생했다. @cupix/forge-agents 라이브러리가 property database의 유효 범위(1~9216)를 초과하는 object ID 9217에 접근을 시도하여 에러가 발생했으며, 동일 BIM 모델에서 2건의 반복 발생이 확인되었다.
Quick Facts#
| Field | Value |
|---|---|
| exception.message | Failed to get node: Failed to get properties and children |
| top_frame | @cupix/forge-agents (외부 패키지, 소스 비공개) |
| runtime | Node.js (filebeat 7.17.15 수집) |
| env | production, us-west-2 |
Timeline#
- 2026-04-14 00:53:16 KST — 동일 패턴의 최초 발생 (다른 모델, object ID: 4435162 vs max 4435158)
- 2026-04-14 21:58:23 KST — 두 번째 발생 (다른 모델, object ID: 1511932 vs max 1511930)
- 2026-04-22 21:26:12 KST — BIM ID 19176 (
HLC_HB.rvt) 첫 번째 처리 시도 및 실패 - 2026-04-23 19:46:13 KST — BIM ID 19176 (
HLC_HB.rvt) 두 번째 처리 시도 및 동일 에러로 실패 - 2026-04-24 — error-sweeper에 의해 클러스터 감지, RCA 수행
Error Log#
Failed to get node: Failed to get properties and children
Impact#
- Service:
cupixworks-any-room-agent - 발생 횟수: 1 (이 클러스터), 전체 동일 패턴 4건 (14일 이내)
- 최초 발생: 2026-04-23T19:46:18.200Z
- 최근 발생: 2026-04-23T19:46:18.200Z
- 영향: BIM 모델 19176의 room extraction이 실패하며, BIM room state가
Error로 설정됨. 해당 모델의 room/workarea 데이터가 생성되지 않아 해당 facility의 room 기반 기능 사용이 불가. SQS 메시지는 삭제되어 자동 재시도되지 않음.
Root Cause Summary#
@cupix/forge-agents 라이브러리(v10.16.0)의 SVF2 property database 순회 로직에서 off-by-one boundary error가 발생한다. 라이브러리가 Autodesk Forge의 SVF2 모델 property database에서 node를 순회할 때, 최대 유효 object ID를 초과하는 ID에 접근을 시도한다. 이 에러는 @cupix/forge-agents 내부에서 발생하며 소스 코드가 비공개(pre-compiled npm 패키지)이므로, 라이브러리 수준에서의 수정이 필요하다. BIM ID 19176 (HLC_HB.rvt)에서 반복 발생(2건)하며, 다른 모델에서도 유사 패턴(object ID가 max 범위를 1~4 초과)이 확인되었다.
Technical Analysis#
Code Path#
- Entry point:
room-service.ts:58—RoomService.run()에서 BIM 모델 처리 시작 room-service.ts:68—runRoomExtractor(cpBim)호출
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);
room-service.ts:187—RoomExtractManager.execute()로 child process 실행 위임
private runRoomExtractor = async (cpBim: CPBim): Promise<void> => {
logger.debug('RoomService::runRoomExtractor | begin');
if (cpBim.forgeUrn == undefined
|| cpBim.forgeFormatType == undefined
) {
throw new Error('RoomService::runRoomExtractor | end - undefined params');
}
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
});
cpBim.fromRoomExtractor(roomExtractorResults);
logger.debug('RoomService::runRoomExtractor | end');
};
room-extract.manager.ts:29—ChildProcessManager.execute()로 자식 프로세스에서 실행
async execute(params: RoomExtractorParams): Promise<RoomExtractorResults> {
logger.debug('RoomExtractManager::execute | begin with urn:', params.urn);
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;
}
}
room-extractor.process.ts:39-44— SVF2 포맷 모델에 대해ForgeAgent.extract()호출
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');
}
-
Failure point:
@cupix/forge-agents내부 — property database 순회 중 object ID 9217 접근 시도 (유효 범위 1~9216). 이 에러는 라이브러리 내부에서 throw되어 상위 catch로 전파됨. -
base-service.ts:290-311— 에러가handlingMessageErrors에서 처리되며,getApiErrorToDeleteMessage에서 에러 객체의response속성이 없어"undefined error"로 분류됨. SQS 메시지 삭제 후 BIM room state를Error로 업데이트.
private getApiErrorToDeleteMessage = (error: any): any => {
if (error == undefined) {
logger.warn('BaseService::getApiErrorToDeleteMessage | undefined error');
return 'undefined error';
Log Evidence#
전체 에러 체인 (모두 동일 시각 2026-04-23T19:46:18.200Z):
service:cupixworks-any-room-agent status:error from:2026-04-23T19:40:00Z to:2026-04-23T19:50:00Z
[2026-04-24 04:46:13 KST] [info] BaseService::runByMessage | id: 19176
[2026-04-24 04:46:14 KST] [info] CupixAuth::setSession | session_id: 01f25334a39bd45ae0a78c996f2b0c743fa71c06
[2026-04-24 04:46:15 KST] [info] RoomExtractManager::execute | urn: dXJuOmFkc2sub2JqZWN0czpvcy5vYmplY3Q6dGVzbGEtcHJvZHVjdGlvbi8xOTE3Nl8xNzc2OTcyODg0ODMzX0hMQ19IQi5ydnQ=
[2026-04-24 04:46:18 KST] [error] Failed to get properties and children: Invalid object ID: 9217. Valid range is 1 to 9216.
[2026-04-24 04:46:18 KST] [error] Failed to get node: Failed to get properties and children
[2026-04-24 04:46:18 KST] [error] Failed to use property database: Failed to get properties and children
[2026-04-24 04:46:18 KST] [error] Failed to traverse nodes: Failed to get properties and children
[2026-04-24 04:46:18 KST] [error] ForgeAgents - Error: { code: 1, message: Failed to get properties and children }
[2026-04-24 04:46:18 KST] [warn] BaseService::getApiErrorToDeleteMessage | undefined error
[2026-04-24 04:46:18 KST] [info] AwsQueueManager::deleteMessage | begin
[2026-04-24 04:46:18 KST] [info] AwsQueueManager::deleteMessage | end
[2026-04-24 04:46:18 KST] [error] BaseService::handlingMessageErrors | Error and message object - {"error":"undefined error","sqsMessage":{"MessageId":"23bb29ea-16f7-4adf-bbb2-8d3b38a34d42","Attributes":{"ApproximateReceiveCount":"1"}}}
Forge URN 디코딩:
urn:adsk.objects:os.object:tesla-production/19176_1776972884833_HLC_HB.rvt
이전 발생 이력 (동일 패턴, 14일 이내):
service:cupixworks-any-room-agent status:error "Invalid object ID" from:2026-04-10T00:00:00Z to:2026-04-24T00:00:00Z
| 시각 | Object ID | Valid Range | BIM ID |
|---|---|---|---|
| 2026-04-14 00:53:16 KST | 4,435,162 | 1 ~ 4,435,158 | 불명 |
| 2026-04-14 21:58:23 KST | 1,511,932 | 1 ~ 1,511,930 | 불명 |
| 2026-04-22 21:26:17 KST | 9,217 | 1 ~ 9,216 | 19176 |
| 2026-04-23 19:46:18 KST | 9,217 | 1 ~ 9,216 | 19176 |
모든 케이스에서 접근 시도한 object ID가 유효 범위의 최대값을 1~4만큼 초과하는 패턴이 확인됨.
Hypotheses Considered#
| # | Hypothesis | Evidence for | Evidence against | Verdict |
|---|---|---|---|---|
| H1 | @cupix/forge-agents의 SVF2 property database 순회 시 off-by-one boundary error |
모든 에러에서 object ID가 max를 1~4 초과; 에러 메시지 "Invalid object ID: 9217. Valid range is 1 to 9216" 직접 확인; ForgeAgent.extract() 호출 직후 발생 |
— | Confirmed |
| H2 | 손상된 BIM 파일(HLC_HB.rvt)로 인해 Forge property database 자체가 비정상 |
BIM ID 19176에서 2회 반복 발생; 동일 object ID boundary (9216/9217) | 다른 모델(4,435,158, 1,511,930)에서도 동일 패턴 발생 — 특정 파일 문제가 아닌 라이브러리 로직 문제 | Rejected |
| H3 | Forge API 서버 측 일시적 오류로 property database 응답이 불완전 | — | 동일 모델에서 동일 boundary(9216/9217)로 재현됨; Forge API 에러가 아닌 로컬 property database 순회 에러 | Rejected |
| H4 | SVF2 manifest가 invalid하여 잘못된 데이터를 반환 | room-extractor.process.ts:48에 SVF2 manifest invalid 시 SVF1 fallback 로직 존재 |
에러가 manifest invalid가 아닌 property database 순회 단계에서 발생; ForgeAgentErrorCode.FORGE_SOURCE_INVALID_MANIFEST가 아닌 다른 에러 |
Rejected |
Fix Recommendation#
즉시 조치 (Critical)#
room-extractor.process.ts:39-53:ForgeAgent.extract()호출 결과에서 property database 관련 에러를 별도로 처리하여, 해당 에러 발생 시 room extraction 결과를 빈 배열(Rooms: [], Levels: [])로 반환하는 graceful degradation 적용. 현재는 에러가 throw되어 전체 처리가 실패하고 BIM state가Error로 설정되지만, property database 순회 실패는 room 정보만 누락될 뿐 BIM 처리 전체를 실패시킬 필요는 없음.
단기 개선 (1주 이내)#
@cupix/forge-agents패키지를 업데이트하여 property database 순회 시 object ID boundary check를 수정. 패키지 관리팀에 "Invalid object ID" 에러에 대한 버그 리포트 및 패치 요청.room-extract.manager.ts:32-41: 에러 로깅 시 에러 객체를 직접 전달하여 스택 트레이스를 보존. 현재logger.error('...', error)형태이나,getApiErrorToDeleteMessage에서"undefined error"로 분류되어 디버깅 정보가 손실됨.
장기 개선 (재발 방지)#
- SVF2 property database 순회 실패 시 SVF1 format으로 fallback하는 로직 추가. 현재
room-extractor.process.ts:48에서FORGE_SOURCE_INVALID_MANIFEST에러에 대해서만 SVF1 fallback이 적용되어 있으나, property database 에러에 대해서도 동일한 fallback 경로를 적용. BaseService.getApiErrorToDeleteMessage()의 에러 분류 로직 개선: 현재error.response가 없으면"undefined error"로 분류하는데, Error 인스턴스의message속성을 활용하여 더 정확한 에러 분류 및 로깅 수행.
Monitoring#
- Property database boundary 에러 모니터링:
service:cupixworks-any-room-agent status:error "Invalid object ID"
- Room extraction 전체 실패율 모니터링:
service:cupixworks-any-room-agent status:error "ForgeAgents - Error"
- BIM Error state 전환 빈도 추적을 위한
updateBimRoomState | state: error로그 모니터링:
service:cupixworks-any-room-agent "updateBimRoomState" "Error"
Risk Assessment#
- Risk level: low
- 예상 복잡도: standard
- 근거: 발생 빈도가 낮고(14일간 4건), 특정 BIM 모델의 property database 구조에 의존하는 문제. room extraction 실패는 해당 facility의 room 기능에만 영향을 미치며, 다른 BIM 처리(forge translation 등)에는 영향 없음. 수정은
@cupix/forge-agents패키지 업데이트 또는 에러 핸들링 개선으로 가능.