흔한 에러 진단 & 해결
흔한 에러 진단 & 해결
텍스트로만 진행되는 튜토리얼입니다 · 예상 소요 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 인스턴스입니다. statusCode와 code로 원인을 정확히 분기할 수 있습니다.
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 이슈로 제보해주세요
이 튜토리얼이 도움이 됐나요?