Files
2nd/10_Wiki/Topic_Programming/Language/에러_처리와_커스텀_에러.md
T
Antigravity Agent e2c5471046 wiki: Topic_Blog 신규 문서 일괄 추가 + ASTRA 성장 자산 동기화
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-16 09:55:38 +09:00

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
error handling
try catch
커스텀 에러
graceful degradation
에러 클래스
rollback
A 0.93 2026-06-13 2026-06-13
typescript
error-handling
robustness
astraai
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
AstraAI

에러 처리와 커스텀 에러

🎯 한 줄 통찰 (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)

에러 클래스 계층

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)

📚 출처 (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 코드 분석 기반 초안 생성.