+ Avoids overclaiming and gives safe, concrete diagnostics.
- It is slightly long due to several low-likelihood causes.
Reads the message, ranks the possible causes, and gives a concrete way to check each one.
| Category | Development › Coding |
|---|---|
| Tags | AnalyzingReviewingDeveloperCode |
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.**
A fix offered before the cause is known usually moves the bug. This ranks causes and says how to verify each before changing anything.
ChatGPT best separates the direct failure from the unconfirmed root cause. Gemini is concrete but overly speculative and suggests risky logging; [C] was not provided.
+ Avoids overclaiming and gives safe, concrete diagnostics.
- It is slightly long due to several low-likelihood causes.
+ Clearly identifies the failure point and concrete checks.
- Ranks a token-refresh race first without enough evidence.
| Criterion | ChatGPT | Gemini | Leader |
|---|---|---|---|
| Instruction following | 10 | 9 | ChatGPT +11% |
| Accuracy | 9 | 6 | ChatGPT +50% |
| Specificity | 10 | 9 | ChatGPT +11% |
| Structure | 9 | 9 | Tie |
| Right length | 8 | 6 | ChatGPT +33% |
Scored 1–10 by gpt-5.6-sol with model names hidden (2026-09-24). This is an AI review, not a measurement.
We gave three models the same input and copied their answers unedited. Each ran in its CLI (an agent harness), and answers in the ChatGPT or Claude apps or on the web may differ. Outputs are in Korean.
Environment: Node.js 20, Express 4, PostgreSQL 15(Docker), 로컬은 macOS, 배포는 스테이징 서버(Ubuntu 22.04, PM2)
Error and stack trace: 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)
Relevant code: // 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();
}
What I was doing: 로그인한 사용자가 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 설정에 있을 가능성이 큽니다.
| 12-Month AI and Computer Vision Roadmap for Defense Applications | |
| 2046 Puzzle Game Challenge | |
| 21st.dev component prompt | |
| 3D FACTORY | |
| 3D FPS Game |