e2c5471046
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
8.5 KiB
8.5 KiB
id, title, category, status, verification_status, canonical_id, aliases, duplicate_of, source_trust_level, confidence_score, created_at, updated_at, review_reason, merge_history, tags, raw_sources, applied_in, github_commit
| id | title | category | status | verification_status | canonical_id | aliases | duplicate_of | source_trust_level | confidence_score | created_at | updated_at | review_reason | merge_history | tags | raw_sources | applied_in | github_commit | ||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| error-handling-custom-errors | 에러 처리와 커스텀 에러 | Programming_Language | draft | applied |
|
A | 0.93 | 2026-06-13 | 2026-06-13 |
|
|
|
에러 처리와 커스텀 에러
🎯 한 줄 통찰 (One-line insight)
견고한 코드는 "실패를 예측해서 분류하고, 사용자에게는 친절히 번역하며, 부가 작업의 실패가 본류를 망가뜨리지 않게" 만든다 — AstraAI 는 커스텀 에러 계층 + 사용자 친화 번역기 + "절대 본 흐름을 깨지 않는 try/catch" 로 이를 구현한다 [S1][S2][S4].
🧠 핵심 개념 (Core concepts)
Error상속 계층: 도메인별 에러를class XError extends Error로 만들어,instanceof로 분기하고 추가 컨텍스트(경로, 엔진, 상태코드)를 담는다 [S1].- 추상 베이스 클래스:
abstract class G1Error extends Error가 공통 형태(details,getTypeCode())를 강제하고, 구체 에러가 타입 코드를 구현 [S1]. - 에러 번역 (Error translation): 내부 기술 에러 메시지를 사용자 행동 지침 으로 변환 (
title/message/action) [S2]. - Graceful degradation: 부가 기능(메모리 추출, 증류, 텔레메트리)의 실패는 삼키고(
catch {}) 본 흐름을 계속한다 [S4]. - 트랜잭션/롤백: 여러 파일 변경을 묶고, 실패 시 백업으로 되돌리는 보상 트랜잭션 [S3].
🧩 추출된 패턴 (Extracted patterns)
- 커스텀 에러에 컨텍스트 부착:
FileSystemError(message, path, details),APICommunicationError(message, engine, status)— 잡는 쪽이 어디서 왜 실패했는지 알 수 있게 [S1]. this.name = this.constructor.name: 스택 트레이스에 정확한 클래스명이 찍히도록 베이스에서 설정 [S1].- "본 흐름을 깨지 않는" catch:
try { extract(); } catch { /* memory extraction should never break the main flow */ }— 의도를 주석으로 명시한 의도적 삼킴 [S4]. - 에러를 Error 로 정규화:
error instanceof Error ? error : new Error(String(error))— catch 의unknown/any를 항상 Error 로 변환 [S5]. - 사용자 친화 번역기: 키워드 매칭(
fetch/timeout/404)으로 정형화된 안내 카드를 반환 [S2]. - 보상 트랜잭션: 변경 전 원본을 백업(
record), 성공 시commit(백업 폐기), 실패 시rollback(원복) [S3].
📖 세부 내용 (Details)
에러 클래스 계층
abstract class G1Error extends Error {
constructor(public message: string, public details?: any) {
super(message);
this.name = this.constructor.name; // 스택에 실제 클래스명
}
abstract getTypeCode(): string; // 하위가 타입 코드 구현 강제
}
export class FileSystemError extends G1Error {
constructor(message: string, public path: string, details?: any) { super(message, details); }
getTypeCode() { return 'FILE_SYSTEM_ERROR'; }
}
abstract 메서드로 모든 하위 에러가 식별 코드를 갖게 강제 — 로깅/분기에서 문자열 비교 대신 안정적 코드를 쓴다 [S1].
"절대 본 흐름을 깨지 않는다"
세션 종료 시 메모리 추출·증류는 부가 작업 이다. 실패해도 대화 자체는 정상이어야 하므로 빈 catch 로 삼키되 왜 삼키는지 주석을 단다:
try { this.extractor.extractFromSession(...); }
catch { /* memory extraction should never break the main flow */ }
무분별한 빈 catch 는 안티패턴이지만, "부가 작업 + 의도 주석" 조합은 의도적 견고성이다 [S4].
사용자 친화 번역
if (msg.includes('timeout')) return {
title: '⏱️ 응답 시간 초과 (Timeout)',
message: 'AI가 답변을 준비하는 데 너무 오래 걸리고 있습니다.',
action: '설정에서 Timeout 시간을 늘리거나, 더 작은 범위로 질문해보세요.',
};
기술 메시지(ECONNREFUSED)를 그대로 노출하지 않고, 무엇을 하면 되는지 를 알려준다. 마지막에 일반 fallback 카드로 미분류 에러를 처리 [S2].
보상 트랜잭션 (파일 작업의 원자성)
DB 트랜잭션이 없는 파일시스템에서 "여러 파일 변경을 전부 성공 또는 전부 취소" 하려면 직접 백업/복원해야 한다. begin → record(각 파일) → (성공) commit / (실패) rollback. rollback 은 created 파일은 삭제, modified 파일은 원본 내용 복원 [S3].
⚖️ 비교 및 선택 기준 (Comparison & decision criteria)
| 항목 (Option) | 장점 | 단점 | 언제 선택 |
|---|---|---|---|
| throw + 상위 catch | 흐름 단순 | 어디서 잡을지 추적 필요 | 계약 위반·복구 불가 상황 |
| 빈 catch (의도 주석) | 본 흐름 보호 | 남용 시 버그 은폐 | 진짜 부가 작업만 |
| 결과 유니온 반환 | 호출부 강제 처리 | 보일러플레이트 | 흔한 실패(파일 append) |
| 커스텀 에러 클래스 | instanceof 분기 + 컨텍스트 | 클래스 정의 비용 | 도메인별 처리 분기 필요 |
⚖️ 모순 및 업데이트 (Contradictions & updates)
- 빈 catch 는 기본적으로 위험: AstraAI 는 "본 흐름을 깨지 않아야 하는 부가 작업"에 한해 의도 주석과 함께만 허용한다. 검증·핵심 로직의 실패는 절대 조용히 삼키지 않는다.
- 에러 메시지 키워드 매칭의 취약성:
ErrorTranslator는 메시지 문자열에 의존하므로, 라이브러리가 메시지를 바꾸면 매칭이 깨질 수 있다. 가능하면getTypeCode()같은 안정 식별자 기반 분기가 더 견고하다.
🛠️ 적용 사례 (Applied in summary)
AstraAI/src/core/errors.ts— G1Error 추상 베이스 + 4개 도메인 에러 [S1].AstraAI/src/core/errorHandler.ts— ErrorTranslator 사용자 친화 번역 [S2].AstraAI/src/core/transaction.ts— begin/record/commit/rollback 보상 트랜잭션 [S3].AstraAI/src/memory/index.ts— "본 흐름 보호" 의도적 빈 catch [S4].
💻 코드 패턴 (Code patterns)
// 1) 컨텍스트를 담는 커스텀 에러 (src/core/errors.ts)
export class APICommunicationError extends G1Error {
constructor(message: string, public engine: string, public status?: number, details?: any) {
super(message, details);
}
getTypeCode() { return 'API_COMMUNICATION_ERROR'; }
}
// 2) catch 의 unknown 을 Error 로 정규화 (src/core/services.ts)
catch (error: any) {
lastError = error instanceof Error ? error : new Error(String(error));
}
// 3) 본 흐름을 깨지 않는 의도적 삼킴 (src/memory/index.ts)
try { distillStaleEpisodes(...); }
catch { /* distillation should never break session end */ }
// 4) 보상 트랜잭션 (src/core/transaction.ts)
tx.begin();
try {
await tx.record(filePath); // 변경 전 백업
fs.writeFileSync(filePath, next);
tx.commit(); // 성공 → 백업 폐기
} catch (e) {
tx.rollback(); // 실패 → 원본 복원
throw e;
}
✅ 검증 상태 및 신뢰도
- 상태: draft
- 검증 단계: applied
- 출처 신뢰도: A
- 신뢰 점수: 0.93
- 중복 검사 결과: 신규 생성 (New discovery)
🔗 지식 그래프 (Knowledge Graph)
- 상위/루트: TypeScript 기초와 타입 시스템
- 관련 개념: 동시성 제어 Lock Queue Transaction, 비동기 프로그래밍 Promise async await, 코딩 컨벤션과 주석 철학
- 참조 맥락: 로컬 LLM 이 실패를 분류·번역·복구하는 코드를 작성할 때 참조.
📚 출처 (Sources)
- [S1] AstraAI/src/core/errors.ts — G1Error 추상 베이스 + 도메인 에러
- [S2] AstraAI/src/core/errorHandler.ts — ErrorTranslator
- [S3] AstraAI/src/core/transaction.ts — 보상 트랜잭션
- [S4] AstraAI/src/memory/index.ts — 의도적 빈 catch
- [S5] AstraAI/src/core/services.ts — Error 정규화
📝 변경 이력 (Change history)
- 2026-06-13: AstraAI 코드 분석 기반 초안 생성.