본문으로 건너뛰기

흔한 에러 진단 & 해결

흔한 에러 진단 & 해결

텍스트로만 진행되는 튜토리얼입니다 · 예상 소요 6분

입문시작하기6분읽기 약 2분업데이트 2026-04-14

401·403·404·429·CORS 등 개발 중 자주 만나는 에러를 원인별로 진단하고 해결하는 디버깅 가이드입니다.

이 튜토리얼에서 배울 내용
ApiError / AuthError 구분과 활용
상태 코드(401·403·404·429)별 원인
429 지수 백오프 재시도
전역 에러 핸들러 설정

흔한 에러 진단 & 해결

개발 중 마주치는 에러의 대부분은 몇 가지 패턴으로 좁혀집니다. 이 가이드는 ConnectBase SDK를 쓰며 자주 보는 에러를 원인 → 해결 순으로 정리합니다.

에러를 읽는 법: ApiError / AuthError

SDK가 던지는 에러는 표준 Error가 아니라 ApiError / AuthError 인스턴스입니다. statusCodecode로 원인을 정확히 분기할 수 있습니다.

typescript
import { ApiError, AuthError } from 'connectbase-client'

try {
  await cb.database.queryData(TABLE_ID, { limit: 10 })
} catch (err) {
  if (err instanceof ApiError) {
    console.log(err.statusCode)  // 401 | 403 | 404 | 429 ...
    console.log(err.code)        // 서버가 분류한 에러 코드 (있을 때)
    console.log(err.message)     // 사람이 읽는 메시지
  } else if (err instanceof AuthError) {
    // 토큰 만료 등 인증 관련 — 로그인 페이지로 보내세요
  }
}

상태 코드별 원인

코드의미가장 흔한 원인
401인증 실패Public Key 누락/오타, 로그인 안 됨, 토큰 만료
403권한 없음키 권한 범위 부족, RLS 정책에 막힘
404대상 없음테이블 ID/리소스 ID 오타, 잘못된 경로
429요청 과다요금제 rate limit 초과

1. "401 Unauthorized"

가장 흔한 원인은 Public Key 문제입니다.

  • .env의 키가 cb_pk_로 시작하는지 확인 (cb_sk_는 서버 전용 Secret Key — 브라우저에서 쓰면 안 됩니다)
  • Vite는 VITE_ 접두사가 붙은 환경변수만 노출합니다 (VITE_CONNECT_BASE_PUBLIC_KEY)
  • .env 수정 후에는 개발 서버를 재시작해야 반영됩니다

앱 멤버 인증이 필요한 호출(파일 업로드, 댓글 등)에서 401이 나면 로그인이 안 된 것입니다 — 회원 인증으로 먼저 로그인하세요.

2. "403 Forbidden"

인증은 됐지만 권한이 없는 경우입니다.

  • 콘솔 → Public Key 설정에서 해당 작업(읽기/쓰기) 권한이 켜져 있는지 확인
  • 테이블에 RLS(행 수준 보안) 정책이 걸려 있으면, 본인 소유 행만 접근 가능합니다 — 정책 조건을 확인하세요

3. "404" — 리소스 없음

  • 테이블 ID가 정확한지 확인하세요. 테이블 ID(UUID) 와 데이터 row의 id는 다른 값입니다
  • ID를 .env에 넣었다면 오타·줄바꿈이 없는지 확인

4. "429 Too Many Requests" — 지수 백오프

요금제의 요청 한도를 넘으면 429가 반환됩니다. 잠시 기다렸다 재시도하되, 지수적으로 간격을 늘리는 것이 정석입니다.

typescript
import { ApiError } from 'connectbase-client'

async function withRetry<T>(fn: () => Promise<T>, maxRetries = 3): Promise<T> {
  for (let attempt = 0; attempt <= maxRetries; attempt++) {
    try {
      return await fn()
    } catch (err) {
      // 429가 아니거나 마지막 시도면 그대로 던집니다
      if (!(err instanceof ApiError) || err.statusCode !== 429 || attempt === maxRetries) {
        throw err
      }
      // 1초 → 2초 → 4초 로 대기
      await new Promise((resolve) => setTimeout(resolve, 2 ** attempt * 1000))
    }
  }
  throw new Error('unreachable')
}

// 사용
const result = await withRetry(() => cb.database.queryData(TABLE_ID, { limit: 50 }))

5. CORS 에러

브라우저 콘솔에 blocked by CORS policy가 보이면, 콘솔 → 보안 설정에서 앱이 실행되는 출처(예: http://localhost:5173)를 허용 목록에 추가하세요.

전역 에러 핸들러

매 호출마다 try/catch를 쓰는 대신, SDK 초기화 시 전역 핸들러를 등록할 수 있습니다.

typescript
import { ConnectBase } from 'connectbase-client'

export const cb = new ConnectBase({
  publicKey: import.meta.env.VITE_CONNECT_BASE_PUBLIC_KEY,
  // 모든 ApiError / AuthError 발생 시 호출 (로깅·모니터링용)
  onError: (err) => {
    console.error('[ConnectBase]', err.name, err.message)
  },
  // 인증 에러(토큰 만료 등) 전용 — 로그인 페이지로 보내기 좋습니다
  onAuthError: () => {
    window.location.href = '/login'
  },
})

그래도 막힌다면

  • 브라우저 네트워크 탭에서 실제 요청 URL·상태 코드·응답 body를 확인하세요 (원인의 상당수가 여기서 바로 보입니다)
  • 흔한 에러 & 해결책 문서에서 더 많은 사례를 확인하세요
  • 재현되는 버그는 GitHub 이슈로 제보해주세요

이 튜토리얼이 도움이 됐나요?