붙여넣은 토큰의 개행 때문에 fetch 가 요청을 보내기 전에 죽었다
The string did not match the expected pattern. 이라는 메시지에는 헤더도 토큰도 안 나옵니다
backend · cover image
새로 붙인 화면에서 API 호출이 전부 실패하는데, 에러 메시지가 이것뿐이었습니다.
The string did not match the expected pattern.
네트워크 탭에는 요청이 아예 없었습니다. 서버에 닿기 전에 브라우저가 던진 것입니다.
- Safari(WebKit) 가 이 문구의
SyntaxError를 던집니다. Chrome 계열은 같은 상황에서Failed to execute 'fetch' on 'Window': Invalid value를 던집니다. - 메시지 어디에도 헤더나 토큰이라는 말이 없어서 URL 문제로 오인하기 쉽습니다.
원인
fetch(url, { headers: { Authorization: `Bearer ${token}` } })
token 에 헤더 값으로 허용되지 않는 문자(개행 등)가 들어 있으면 브라우저가 Headers 를 만드는 단계에서 예외를 던집니다.
토큰을 개발자도구 콘솔이나 .env 에 손으로 붙여넣는 개발 초기 단계에서 잘 생깁니다.
- 메신저나 문서에서 복사하며 딸려 온 개행과 공백
- 값에 같이 넣은 따옴표 (
"eyJ...") Bearer eyJ...처럼 접두어까지 통째로 저장한 경우. 이건 예외는 아니고Bearer Bearer ...가 되어 401 이 납니다.
로그인 화면이 생기기 전까지 localStorage 와 환경변수로 토큰을 주입하고 있었는데, 거기 붙여넣은 값에 개행이 섞여서 화면 전체가 이 에러로 죽었습니다.
해결
토큰을 읽는 단일 지점에서 정리한 뒤 순수 토큰만 헤더에 넣습니다.
export function getToken() {
const raw = localStorage.getItem(TOKEN_KEY) ?? import.meta.env.VITE_API_TOKEN ?? ''
return raw
.trim()
.replace(/^["']|["']$/g, '') // 앞뒤 따옴표
.replace(/^Bearer\s+/i, '') // 접두어 중복
.replace(/\s+/g, '') // 중간 개행·공백
}
localStorage 값이 환경변수보다 우선하는 구조라면, 환경변수로 갈아탈 때 브라우저에서 localStorage.removeItem(TOKEN_KEY) 로 깨진 값을 지워야 합니다. 코드를 고쳐도 저장된 값이 계속 먼저 읽힙니다.