sayu.day
Backend

Go 에러 핸들링 전략 실무 가이드

Go에서 errors.Is/As, 래핑, 도메인 에러를 실무적으로 적용하는 기준을 정리합니다.

발행 2026년 1월 2일2350

같은 주제에서 이어 읽기

Go 인터페이스 설계 원칙 - Accept Interfaces, Return Structs

Backend 안에서 이어지는 글

핵심 원칙

  • 에러는 문자열이 아니라 의미 있는 값으로 다룹니다.
  • 상위 계층으로 올릴 때는 %w원인 체인을 유지합니다.
  • 분기 판단은 문자열 비교가 아니라 errors.Is, errors.As를 사용합니다.

1) 래핑: %w를 기본으로

func readConfig(path string) error {
	if _, err := os.ReadFile(path); err != nil {
		return fmt.Errorf("config read failed: %w", err)
	}
	return nil
}

%v를 쓰면 원인 에러를 잃어버립니다. 에러 전달 경로에서는 %w를 기본으로 두세요.

2) errors.Is로 분기

var ErrNotFound = errors.New("not found")

func findUser(id string) (*User, error) {
	u, err := repo.Find(id)
	if errors.Is(err, sql.ErrNoRows) {
		return nil, ErrNotFound
	}
	if err != nil {
		return nil, fmt.Errorf("find user: %w", err)
	}
	return u, nil
}

호출부는 체인 전체에서 의미를 찾습니다.

if errors.Is(err, ErrNotFound) {
	// 404
}

3) errors.As로 타입 추출

type ValidationError struct {
	Field string
	Msg   string
}

func (e *ValidationError) Error() string {
	return fmt.Sprintf("invalid %s: %s", e.Field, e.Msg)
}
var vErr *ValidationError
if errors.As(err, &vErr) {
	log.Printf("field=%s msg=%s", vErr.Field, vErr.Msg)
}

4) 도메인 에러로 HTTP 매핑

type Code string

const (
	CodeNotFound Code = "NOT_FOUND"
	CodeConflict Code = "CONFLICT"
)

type DomainError struct {
	Code  Code
	Msg   string
	Cause error
}

func (e *DomainError) Error() string { return e.Msg }
func (e *DomainError) Unwrap() error { return e.Cause }

핸들러에서는 도메인 코드만 보고 응답을 결정합니다.

func toStatus(code Code) int {
	switch code {
	case CodeNotFound:
		return http.StatusNotFound
	case CodeConflict:
		return http.StatusConflict
	default:
		return http.StatusInternalServerError
	}
}

운영에서 중요한 규칙

  • 에러 메시지는 사용자 메시지와 내부 로그 메시지를 분리합니다.
  • 재시도 여부(temporary/permanent)를 코드 또는 타입으로 표현합니다.
  • 로그는 "한 번만" 책임 계층에서 남깁니다. (중복 로깅 금지)

피해야 할 패턴

  • if err != nil { return errors.New("...") }로 원인 손실
  • err.Error() 문자열 포함 여부로 분기
  • 패키지 전역 센티넬 에러를 과도하게 남발

요약

Go 에러 전략의 핵심은 단순합니다.

  • 래핑은 %w
  • 분기는 Is/As
  • 외부 계약은 도메인 에러 코드

이 세 가지를 팀 규칙으로 고정하면 장애 대응 속도와 코드 일관성이 크게 좋아집니다.

다음 읽기

이 생각이 이어지는 방향

Backend 더 보기
공유

읽은 뒤의 대화

읽은 뒤의 생각을 이어갑니다

질문, 반론, 조용한 후속 메모를 이 글 아래에 남길 수 있습니다.

sayu.day는 생각과 작업의 흔적을 천천히 정리하는 개인 출판물입니다.
직접 겪고 검토한 내용, 다시 읽을 만한 아이디어, 작업하며 남긴 메모를 모읍니다.
시간이 지난 글은 현재의 판단과 다를 수 있어 업데이트 맥락을 함께 남깁니다.

© 2026 sayu.day