Skip to content
Merged
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 17 additions & 12 deletions src/api/core/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
import { notFound, redirect } from 'next/navigation';

import axios from 'axios';

import { CommonErrorResponse, CommonSuccessResponse } from '@/types/service/common';
Expand Down Expand Up @@ -37,16 +35,6 @@ baseAPI.interceptors.response.use(
return response;
},
async (error) => {
const status = error.response?.status;
if (status) {
if (status === 401) {
redirect('/signin?error=unauthorized');
}
if (status === 404) {
notFound();
}
}

const errorResponse: CommonErrorResponse = error.response?.data || {
type: 'about:blank',
title: 'Network Error',
Expand All @@ -56,6 +44,23 @@ baseAPI.interceptors.response.use(
errorCode: 'NETWORK_ERROR',
};

const { status } = errorResponse;
const isServer = typeof window === 'undefined';

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

HTTP status 분기 기준이 payload(errorResponse.status)라 오동작 여지 있음
Axios의 실제 상태코드(error.response?.status)를 1순위로 쓰고, payload status는 fallback으로 두는 편이 안전합니다.

-    const { status } = errorResponse;
+    const status = error.response?.status ?? errorResponse.status;
     const isServer = typeof window === 'undefined';
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const { status } = errorResponse;
const isServer = typeof window === 'undefined';
const status = error.response?.status ?? errorResponse.status;
const isServer = typeof window === 'undefined';
🤖 Prompt for AI Agents
In src/api/core/index.ts around lines 47-49, the code currently uses payload
status (errorResponse.status) as the primary HTTP status which can misbehave;
change the logic to prefer Axios' actual HTTP status (error.response?.status)
first and only fall back to errorResponse.status when that is undefined or null,
ensuring you safely access error.response and handle undefined values before
assigning to the status variable so downstream branches use the real HTTP
status.

if (status === 401) {
if (isServer) {
const { redirect } = await import('next/navigation');
redirect('/login');
} else {
const currentPath = window.location.pathname + window.location.search;
window.location.href = `/login?error=unauthorized&path=${encodeURIComponent(currentPath)}`;
}
}
Comment on lines 50 to 61
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

401 클라이언트 리다이렉트는 /login에서 루프 가능성 가드 필요
로그인 페이지에서 401이 다시 터지면 /login?...로 계속 이동할 수 있어, 최소한 현재 경로가 /login일 때는 리다이렉트를 스킵하는 방어 로직을 권장합니다.

     } else {
+        if (window.location.pathname === '/login') {
+          throw errorResponse;
+        }
         const currentPath = window.location.pathname + window.location.search;
         window.location.href = `/login?error=unauthorized&path=${encodeURIComponent(currentPath)}`;
     }

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In src/api/core/index.ts around lines 50-58, the redirect-on-401 logic needs a
guard to avoid redirect loops back to /login; before calling redirect('/login')
on the server, obtain the current request path from the server request/context
and skip the redirect if the path is '/login' (or startsWith '/login');
similarly on the client, check window.location.pathname (or pathname+search) and
only set window.location.href to the login URL when the current path is not
'/login' (or doesn’t start with '/login') so repeated 401s on the login page
won’t trigger continuous redirects.

if (status === 404) {
const { notFound } = await import('next/navigation');
notFound();
}

Comment on lines 50 to 68
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🌐 Web query:

Next.js notFound() function server-only api client-side compatibility

💡 Result:

Short answer: notFound() is a server-only API — it is designed to be called from Server Components, route handlers, or Server Functions (files/functions marked to run on the server). Calling notFound() from a Client Component will not work and will produce errors; instead you must either (a) perform the check on the server and call notFound() there, or (b) call a server action (a function marked "use server") which calls notFound(), or (c) handle navigation on the client (e.g. router.replace to a 404 route or your custom not-found UI). [1][2][3]

Pointers and sources:

  • notFound() docs (server-only behavior & usage examples). [1]
  • Server Functions / "use server" — create server functions that client code can call to run server-only logic (including calling notFound()). [2]
  • Explanation of server-only vs client bundles and the server-only package (prevents importing server-only code into client). Useful when you want to ensure not to leak server-only code into the client. [3]

If you want, tell me which component/file you’re trying to call notFound() from and I’ll give a concrete refactor (server function pattern or client navigation) with code.


🌐 Web query:

Next.js app router next/navigation notFound() can be called from client component

💡 Result:

Short answer: No — notFound() is a server-side App‑Router function and cannot be directly invoked inside a Client Component. Use a server-side route/handler or a Server Action to call notFound(), or navigate the client to a 404 route (e.g. router.push('/404')) from the client instead. [1][2]

References

  • notFound() docs (throws to terminate server rendering / used inside route segments). [1]
  • redirect() docs (explicitly shows client usage for redirect to contrast behavior). [2]

Sources

  1. Next.js docs — notFound. [1]
  2. Next.js docs — redirect (Client Component example). [2]

🌐 Web query:

Next.js "use server" directive notFound() next/navigation client-side runtime error

💡 Result:

Likely cause

  • You're calling notFound() or using the "use server" directive from code that Next.js is treating as a Client Component (or importing a "use server" file into something that runs on the client). notFound() and Server Functions must run in server context; "use server" files must only export async server functions and cannot be shipped to the browser. [1][2]

How to fix (short)

  1. Ensure the module that calls notFound() is a Server Component (no "use client" at top). notFound() is server-only. [1]
  2. If you need a Server Action callable from the client, put it in its own file with 'use server' at the very top and export an async function; import that server file only into Server Components and pass the function to Client Components via props. Do NOT put 'use server' inside a file that Next treats as a client component. [2][3]
  3. Verify exported values in 'use server' files are async functions (not objects/values). If any export is non-async, you’ll get the invalid "use server" value error. [3]
  4. Check your import graph: a server-only file must not be imported (directly or transitively) into a client component. Move shared code into server-safe or client-safe modules accordingly. [2][3]

If you want, paste the minimal file(s) (page/component + any imports) and I’ll point exactly which file should be server vs client and what to change.

Sources

  • notFound() docs. [1]
  • 'use server' directive docs + Server Actions guidance. [2]
  • Invalid "use server" value / common errors. [3]

References
[1] Next.js — Functions: notFound.
[2] Next.js — Directives: 'use server'.
[3] Next.js — Invalid "use server" Value.


클라이언트에서 notFound() 호출은 런타임 에러 발생(서버 전용 API)

현재 코드(59-62줄)는 클라이언트에서도 next/navigationnotFound()를 호출합니다. notFound()는 Next.js 서버 전용 API로, 클라이언트 측에서 실행되면 런타임 크래시가 발생합니다. 401 처리와 동일하게 isServer로 분기하여 서버에서는 notFound() 호출, 클라이언트에서는 /404로 이동하도록 처리해야 합니다.

-    if (status === 404) {
-      const { notFound } = await import('next/navigation');
-      notFound();
-    }
+    if (status === 404) {
+      if (isServer) {
+        const { notFound } = await import('next/navigation');
+        notFound();
+      } else {
+        window.location.href = '/404';
+      }
+    }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if (status === 401) {
if (isServer) {
const { redirect } = await import('next/navigation');
redirect('/login');
} else {
const currentPath = window.location.pathname + window.location.search;
window.location.href = `/login?error=unauthorized&path=${encodeURIComponent(currentPath)}`;
}
}
if (status === 404) {
const { notFound } = await import('next/navigation');
notFound();
}
if (status === 401) {
if (isServer) {
const { redirect } = await import('next/navigation');
redirect('/login');
} else {
const currentPath = window.location.pathname + window.location.search;
window.location.href = `/login?error=unauthorized&path=${encodeURIComponent(currentPath)}`;
}
}
if (status === 404) {
if (isServer) {
const { notFound } = await import('next/navigation');
notFound();
} else {
window.location.href = '/404';
}
}
🤖 Prompt for AI Agents
In src/api/core/index.ts around lines 50 to 63, the code calls next/navigation's
notFound() unconditionally which will crash on the client; update the 404
handling to mirror the 401 branch by checking isServer: if isServer, import and
call notFound(); else, compute current path if needed and set
window.location.href to '/404' (or '/404?path=...' if you want to preserve path)
so client-side navigation doesn't call the server-only API.

throw errorResponse;
},
);
Expand Down