Server Error
Error: Error serializing .initialState.user.auth.error
returned from getServerSideProps
in "/".
Reason: undefined
cannot be serialized as JSON. Please use null
or omit this value.
정말 간단한 부분에서 발생했는데 한참을 헤맸던 에러였다.
먼저 내용을 읽어보면 getServerSideProps
에서 .initialState.user.auth.error
를 직렬화하는 과정에서 에러가 발생했고, undefined은 JSON으로 직렬화할 수 없으니 null을 사용하거나 생략하라고 친절히 말해주고 있다.
여기서 주목해야 할 것은 .initialState.user.auth.error
이다.
말 그대로 사용자 인증의 error
부분에서 에러가 생긴 상황이란 얘기다(에러탈트붕괴현상...🤦♀️).
나는 error
가 그 error
를 말하는 거라는 생각을 못해 괜히 서버 코드를 뒤적거리고 멀쩡한 코드만 지웠다가 추가했다가 시간을 낭비했는데 결국 에러 내용에 답이 있었다.
export const authServersiceAction = async (context: ContextType): Promise<void> => {
const cookie = context.req ? context.req.headers.cookie : '';
axios.defaults.headers.Cookie = '';
if (context.req && cookie) {
axios.defaults.headers.Cookie = cookie;
}
await context.store.dispatch(authAction(null)); // authAction에서 에러 발생
};
// 로그인 인증
export const authAction = createAsyncThunk<User, null, { rejectValue: MyKnownError }>(
'user/auth',
async (_, { rejectWithValue }) => {
try {
const { data } = await axios.get(`/auth`);
return data;
} catch (e) {
console.error(e);
return rejectWithValue({ message: e.response.data });
}
}
);
서버사이드렌더링 시 쿠키를 공유하는 함수에서 authAction
을 디스패치하는 코드 한줄을 지우니 에러가 발생하지 않았다. 이것을 바탕으로 추적해보니 authAction
은 로그인 인증에 관한 thunk
함수인데 여기서 에러를 리턴하는 과정에서 e.response.data
에 undefined
이 담긴 것이 원인이었다.
그렇다면 e.response.data
에 왜 undefined
이 담겼을까?
이는 리덕스 툴킷의 createAsyncThunk
으로 비동기를 처리하는 과정에서 rejectWithValue
속성을 사용하는데, rejectWithValue
의 값인 RejectValue
가 undefined
으로 정의되어 있기 때문이다. 아래를 보면 확인할 수 있다.
declare type BaseThunkAPI<S, E, D extends Dispatch = Dispatch, RejectedValue = undefined> = {
dispatch: D;
getState: () => S;
extra: E;
requestId: string;
signal: AbortSignal;
rejectWithValue(value: RejectedValue): RejectWithValue<RejectedValue>;
};
그래서 thunk
함수에서 예상되는 오류 형식을 다음과 같이 인터페이스로 만들어 오류 값으로 반환하는 작업까지 해주었는데, 이것 대신 e.response.data
를 사용해서 발생한 문제였다.
interface MyKnownError {
message: string;
}
{ rejectValue: MyKnownError }
다음과 같이 e.message
로 수정하여 오류를 해결할 수 있었다.
export const authAction = createAsyncThunk<User, null, { rejectValue: MyKnownError }>(
'user/auth',
async (_, { rejectWithValue }) => {
try {
const { data } = await axios.get(`/auth`);
return data;
} catch (e) {
console.error(e);
return rejectWithValue({ message: e.message });
}
}
);
에러를 해결할 때, 구글링도 중요하지만 에러 내용, 그리고 내가 작성한 코드를 좀 더 파헤쳐보는 습관을 가져야겠다.