+ 추측을 절제하고 안전한 진단법까지 제시했다.
- 일부 낮은 가능성의 원인까지 다뤄 다소 길다.
에러 로그를 넣으면 원인 후보를 가능성 순으로 줍니다. 바로 코드를 고쳐주는 대신 무엇을 확인해야 하는지 순서를 알려줍니다.
| 분류 | 개발 › 코딩 |
|---|---|
| 태그 | 분석검토개발자코드 |
Find the cause of this error. ***Do not open with a patch.*** Order: 1. **Read the error message** — what failed, and where. 2. List the possible causes, **ordered by likelihood.** 3. Per cause, **how to check it** — concretely. Which file, which line, what to print. 4. Then a fix for the most likely cause. 5. ***If what I gave you is not enough to decide, ask for what is missing. Do not settle it with a guess.*** 6. **Raise the possibility that the problem is in code or config I did not show you.**
에러가 났을 때 바로 수정본부터 받으면 원인을 모른 채로 증상만 옮긴다. 이 프롬프트는 에러 메시지를 먼저 해석하고 가능한 원인을 가능성 순으로 세운 뒤, 각각을 어느 파일 어느 줄에서 어떻게 확인하는지 알려준다. 정보가 부족하면 추측으로 단정하지 않고 무엇을 더 달라고 묻는다.
ChatGPT가 직접 원인과 미확정 근본 원인을 가장 정확히 구분했다. Gemini는 구체적이지만 추측과 위험한 로그 제안이 있고, [C]는 제공되지 않았다.
+ 추측을 절제하고 안전한 진단법까지 제시했다.
- 일부 낮은 가능성의 원인까지 다뤄 다소 길다.
+ 직접 오류 지점과 점검 위치를 구체적으로 짚었다.
- 토큰 갱신 경쟁을 근거 없이 최우선으로 단정했다.
| 기준 | ChatGPT | Gemini | 앞선 모델 |
|---|---|---|---|
| 지시 준수 | 10 | 9 | ChatGPT +11% |
| 정확성 | 9 | 6 | ChatGPT +50% |
| 구체성 | 10 | 9 | ChatGPT +11% |
| 구성·가독성 | 9 | 9 | 동점 |
| 분량 적정성 | 8 | 6 | ChatGPT +33% |
gpt-5.6-sol가 모델 이름을 가린 채 1~10점으로 채점했습니다 (2026-09-24). 측정값이 아니라 AI 심사 결과입니다.
같은 입력을 세 모델에 넣어 받은 답을 그대로 옮겼습니다. 각 CLI(에이전트 하네스)에서 실행했습니다. ChatGPT·Claude 앱이나 웹에서는 답이 다를 수 있습니다.
환경: Node.js 20, Express 4, PostgreSQL 15(Docker), 로컬은 macOS, 배포는 스테이징 서버(Ubuntu 22.04, PM2)
에러: TypeError: Cannot read properties of undefined (reading 'id')
at OrderService.createOrder (/src/services/orderService.js:42:19)
at OrderController.create (/src/controllers/orderController.js:18:35)
코드: // orderController.js
async function create(req, res) {
const order = await OrderService.createOrder(req.user, req.body.items);
res.json(order);
}
// orderService.js
async function createOrder(user, items) {
const order = { userId: user.id, items }; // 42번째 줄
return await db.orders.insert(order);
}
// authMiddleware.js
async function authMiddleware(req, res, next) {
const token = req.headers.authorization?.split(' ')[1];
if (token) {
req.user = await verifyToken(token);
}
next();
}
작업 상황: 로그인한 사용자가 POST /api/orders를 호출할 때 간헐적으로 발생. 로컬에서는 재현이 안 되고 스테이징 서버에서 하루 3~4번 랜덤하게 발생함. 같은 사용자가 같은 요청을 다시 보내면 성공하는 경우가 많음에러의 직접 원인은 user가 undefined인데 orderService.js:42에서 user.id를 읽으려 한 것입니다.
호출 흐름은 다음과 같습니다.
orderController.js:18
OrderService.createOrder(req.user, ...)
orderService.js:42
user.id ← user가 undefined
req.user를 설정하지 않은 채 next() 호출가장 가능성이 높습니다.
현재 코드는 토큰이 없거나 verifyToken() 결과가 undefined여도 요청을 계속 통과시킵니다.
if (token) {
req.user = await verifyToken(token);
}
next();
특히 다음 경우 모두 통과합니다.
Authorization 헤더 없음Authorization: Bearer처럼 토큰이 비어 있음verifyToken(token)이 undefined 반환undefined 반환확인할 곳:
authMiddleware.js의 token 추출 직후verifyToken 구현부/api/orders 라우터에서 authMiddleware가 실제로 등록됐는지임시 로그는 토큰 원문을 출력하지 말고 다음처럼 확인합니다.
console.log({
path: req.originalUrl,
hasAuthorization: Boolean(req.headers.authorization),
scheme: req.headers.authorization?.split(' ')[0],
hasToken: Boolean(token),
});
verifyToken 직후에는:
const verifiedUser = await verifyToken(token);
console.log({
verified: Boolean(verifiedUser),
userId: verifiedUser?.id,
});
req.user = verifiedUser;
스테이징에서 verified: false가 발생하면 이 원인이 확인됩니다.
verifyToken()이 만료·잘못된 토큰을 undefined로 반환간헐적이고 재시도 시 성공하는 현상과도 맞습니다. 예를 들어 토큰 만료, 토큰 갱신 타이밍, 서로 다른 서버의 JWT 설정 차이 등이 있을 수 있습니다.
확인할 곳:
verifyToken 함수verifyToken 내부에서는 토큰 자체 대신 다음 정보를 로깅합니다.
console.log({
pid: process.pid,
nodeEnv: process.env.NODE_ENV,
hasJwtSecret: Boolean(process.env.JWT_SECRET),
});
검증 실패를 삼키고 있다면 원인을 구분해서 기록해야 합니다.
try {
return jwt.verify(token, process.env.JWT_SECRET);
} catch (err) {
console.error('JWT verification failed', {
name: err.name,
message: err.message,
});
return undefined;
}
비밀키나 토큰 원문은 로그에 남기면 안 됩니다.
/api/orders 라우트에서 인증 미들웨어가 누락되거나 순서가 잘못됨확인할 곳:
routes/orderRoutes.jsapp.js 또는 server.js/api/orders를 app.use()로 등록하는 부분다음처럼 인증 미들웨어가 컨트롤러보다 앞에 있어야 합니다.
router.post('/orders', authMiddleware, OrderController.create);
또는:
app.use('/api', authMiddleware, orderRoutes);
router.post() 등록부에 실제 미들웨어가 있는지 출력하거나, 미들웨어 진입 로그를 추가해 확인합니다.
console.log('auth middleware entered', req.method, req.originalUrl);
이 로그 자체가 없는 요청이면 라우팅 또는 미들웨어 등록 문제입니다.
Authorization 헤더 형식이 일부 클라이언트에서 다름현재 구현은 헤더가 반드시 다음 형식이라고 가정합니다.
Authorization: Bearer <token>
다음과 같은 입력은 문제가 될 수 있습니다.
authorization 헤더 누락Bearer만 전달Basic ...확인할 것은 토큰 원문이 아니라 형식입니다.
const parts = req.headers.authorization?.trim().split(/\s+/);
console.log({
partCount: parts?.length,
scheme: parts?.[0],
tokenPresent: Boolean(parts?.[1]),
});
스테이징 앞단의 Nginx, 로드밸런서, API 프록시가 Authorization 헤더를 전달하는지도 확인해야 합니다.
하루 몇 번 랜덤하게 발생하고 같은 요청 재시도는 성공한다면, PM2의 특정 프로세스만 잘못된 설정이나 오래된 코드를 사용하고 있을 가능성도 있습니다.
확인할 것:
pm2 list
pm2 env <process-id>
pm2 logs <app-name> --lines 200
각 요청 로그에 다음을 포함하세요.
console.log({
pid: process.pid,
hostname: require('os').hostname(),
buildVersion: process.env.BUILD_VERSION,
userId: req.user?.id,
});
실패 요청이 특정 pid 또는 특정 호스트에 집중되면 PM2 프로세스별 환경변수, 배포 상태, 재시작 여부를 비교해야 합니다.
현재 인증 실패를 주문 생성까지 통과시키는 것이 직접적인 코드 결함입니다. 인증 미들웨어는 req.user가 없으면 즉시 401을 반환해야 합니다.
async function authMiddleware(req, res, next) {
try {
const parts = req.headers.authorization?.trim().split(/\s+/);
const token = parts?.[0] === 'Bearer' ? parts[1] : undefined;
if (!token) {
return res.status(401).json({ error: 'Authentication required' });
}
const user = await verifyToken(token);
if (!user?.id) {
return res.status(401).json({ error: 'Invalid authentication token' });
}
req.user = user;
return next();
} catch (err) {
console.error('Authentication failed', {
name: err.name,
message: err.message,
});
return res.status(401).json({ error: 'Invalid authentication token' });
}
}
컨트롤러에도 방어 검사를 추가할 수 있습니다.
if (!req.user?.id) {
return res.status(401).json({ error: 'Authentication required' });
}
다만 이것은 최종 원인을 확정하는 로그와 검사가 아닙니다. 현재 제공된 코드만으로는 req.user가 왜 undefined가 됐는지—토큰 누락, verifyToken 실패, 라우팅 누락, 프록시 문제, PM2 설정 불일치—를 결정할 수 없습니다.
정확히 확정하려면 다음이 추가로 필요합니다.
verifyToken() 구현/api/orders 라우터 등록 코드Authorization 헤더 형식 정보또한 문제는 제시되지 않은 코드나 설정, 특히 verifyToken, 라우터 등록부, 프록시 설정, PM2 ecosystem 설정에 있을 가능성이 큽니다.
| 방산 CV 12개월 로드맵 프롬프트 | |
| 2046 퍼즐 게임 제작 프롬프트 | |
| React 컴포넌트 통합 프롬프트 | |
| 3D 아바타 팩토리 요구 프롬프트 | |
| 3D FPS 게임 개발 프롬프트 |