---
id: error-handling-custom-errors
title: "에러 처리와 커스텀 에러"
category: "Programming_Language"
status: "draft"
verification_status: "applied"
canonical_id: ""
aliases: ["error handling", "try catch", "커스텀 에러", "graceful degradation", "에러 클래스", "rollback"]
duplicate_of: ""
source_trust_level: "A"
confidence_score: 0.93
created_at: 2026-06-13
updated_at: 2026-06-13
review_reason: ""
merge_history: []
tags: ["typescript", "error-handling", "robustness", "astraai"]
raw_sources: ["AstraAI/src/core/errors.ts", "AstraAI/src/core/errorHandler.ts", "AstraAI/src/core/transaction.ts", "AstraAI/src/memory/index.ts", "AstraAI/src/core/services.ts"]
applied_in: ["AstraAI"]
github_commit: ""
---

# [[에러 처리와 커스텀 에러]]

## 🎯 한 줄 통찰 (One-line insight)
견고한 코드는 "실패를 *예측해서 분류하고*, 사용자에게는 친절히 번역하며, 부가 작업의 실패가 본류를 망가뜨리지 않게" 만든다 — AstraAI 는 커스텀 에러 계층 + 사용자 친화 번역기 + "절대 본 흐름을 깨지 않는 try/catch" 로 이를 구현한다 [S1][S2][S4].

## 🧠 핵심 개념 (Core concepts)
1. **`Error` 상속 계층:** 도메인별 에러를 `class XError extends Error` 로 만들어, `instanceof` 로 분기하고 추가 컨텍스트(경로, 엔진, 상태코드)를 담는다 [S1].
2. **추상 베이스 클래스:** `abstract class G1Error extends Error` 가 공통 형태(`details`, `getTypeCode()`)를 강제하고, 구체 에러가 타입 코드를 구현 [S1].
3. **에러 번역 (Error translation):** 내부 기술 에러 메시지를 *사용자 행동 지침* 으로 변환 (`title`/`message`/`action`) [S2].
4. **Graceful degradation:** 부가 기능(메모리 추출, 증류, 텔레메트리)의 실패는 삼키고(`catch {}`) 본 흐름을 계속한다 [S4].
5. **트랜잭션/롤백:** 여러 파일 변경을 묶고, 실패 시 백업으로 되돌리는 보상 트랜잭션 [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)
### 에러 클래스 계층
```typescript
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 로 삼키되 **왜 삼키는지 주석을 단다**:
```typescript
try { this.extractor.extractFromSession(...); }
catch { /* memory extraction should never break the main flow */ }
```
무분별한 빈 catch 는 안티패턴이지만, "부가 작업 + 의도 주석" 조합은 의도적 견고성이다 [S4].

### 사용자 친화 번역
```typescript
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)
```typescript
// 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 코드 분석 기반 초안 생성.
