DEV Community

Cover image for 7 Developer Bugs That Waste Hours and How to Fix Them Fast
Valipireddy Kowshik
Valipireddy Kowshik

Posted on

7 Developer Bugs That Waste Hours and How to Fix Them Fast

Every developer has lost an afternoon to a bug that turned out to be a one-line fix. This post covers seven common ones across frontend, backend, and DevOps, with the fix for each.

1. CORS errors: "No 'Access-Control-Allow-Origin' header"

The problem: Your frontend calls your API and the browser blocks it.

Why it happens: CORS is enforced by the browser, and the server has to opt in. Changing frontend code won't fix it.

The fix (Express):

​

import cors from "cors";

app.use(cors({
  origin: ["http://localhost:3000", "https://yourapp.com"],
  methods: ["GET", "POST", "PUT", "DELETE"],
  credentials: true,
}));
​```



**Gotcha:** If you use `credentials: true`, you can't use `origin: "*"`. List your origins explicitly. Also check that your server handles `OPTIONS` preflight requests.

## 2. The N+1 query problem

**The problem:** Your API is slow, and the logs show hundreds of near-identical queries.

​

```javascript
// Bad: 1 query for posts + N queries for authors
const posts = await Post.findAll();
for (const post of posts) {
  post.author = await User.findByPk(post.authorId);
}
​```



**The fix:** Use eager loading or a join.

​

```javascript
// Good: 1-2 queries total
const posts = await Post.findAll({ include: [User] });
​```



**Tip:** Turn on query logging in development. N+1 problems are easy to spot once you can see the SQL.

## 3. Forgetting `await` (and unhandled promise rejections)

**The problem:** Your function "works" but returns `Promise { <pending> }`, or crashes Node with an unhandled rejection.

​

```javascript
// Bug: errors are swallowed, order isn't guaranteed
items.forEach(async (item) => {
  await saveItem(item);
});
​```



**The fix:** `forEach` doesn't wait for async callbacks. Use `for...of` for sequential work or `Promise.all` for parallel work.

​

```javascript
// Sequential
for (const item of items) await saveItem(item);

// Parallel
await Promise.all(items.map(saveItem));
​```



Always wrap the top-level call in `try/catch`, or attach `.catch()`.

## 4. Secrets committed to Git

**The problem:** An API key or {% raw %}`.env`{% endraw %} file ends up in your repo. Bots scan public GitHub constantly, so a leaked key can be abused within minutes.

**The fix:**

1. **Rotate the key immediately.** Deleting the commit isn't enough, because the key is still in history.
2. Add `.env` to `.gitignore`.
3. Scrub history with `git filter-repo` or BFG Repo-Cleaner.
4. Add a pre-commit scanner like `gitleaks` or `trufflehog`.

​

```bash
# .gitignore
.env
.env.*
!.env.example
​```



Commit a `.env.example` with fake values so teammates know what's required.

## 5. Docker builds that never use the cache

**The problem:** Every {% raw %}`docker build`{% endraw %} reinstalls all your dependencies.

​
{% raw %}
```dockerfile
# Bad: any code change invalidates the npm install layer
COPY . .
RUN npm install
​```
{% endraw %}


**The fix:** Order layers from least to most frequently changed.

​
{% raw %}
```dockerfile
# Good: dependencies are cached until package files change
COPY package*.json ./
RUN npm ci
COPY . .
​```
{% endraw %}


Add a {% raw %}`.dockerignore`{% endraw %} (with {% raw %}`node_modules`{% endraw %}, {% raw %}`.git`{% endraw %}, and {% raw %}`dist`{% endraw %}) to keep the build context small.

## 6. React: infinite re-renders and stale state

**The problem:** {% raw %}`Too many re-renders`{% endraw %}, or a {% raw %}`useEffect`{% endraw %} that runs forever.

​
{% raw %}
```javascript
// Bug: new object every render, so the effect re-fires every time
useEffect(() => {
  fetchData(options);
}, [options]); // options = { page: 1 } defined inline
​```
{% endraw %}


**The fix:** Memoize objects and functions used in dependency arrays, or depend on primitives.

​
{% raw %}
```javascript
const options = useMemo(() => ({ page }), [page]);
useEffect(() => { fetchData(options); }, [options]);
​```
{% endraw %}


If state looks stale inside a callback, use the functional update form: {% raw %}`setCount(c => c + 1)`{% endraw %}.

## 7. Memory leaks in long-running Node.js services

**The problem:** Memory climbs until the process crashes with {% raw %}`JavaScript heap out of memory`{% endraw %}.

**Common causes:**
- Event listeners added but never removed
- Unbounded in-memory caches (a plain {% raw %}`Map`{% endraw %} that only grows)
- Timers ({% raw %}`setInterval`{% endraw %}) that are never cleared
- Closures holding references to large objects

**How to find it:**

​
{% raw %}
```bash
node --inspect app.js
# Open chrome://inspect, take heap snapshots, compare them
​```
{% endraw %}


Take one snapshot at startup and another after load, then look at what's growing. For caches, use an LRU cache with a max size instead of a bare `Map`.

## Debugging checklist

When you're stuck, run through this:

- [ ] Can I reproduce it reliably?
- [ ] What changed since it last worked? ({% raw %}`git bisect`{% endraw %} helps)
- [ ] Am I reading the *actual* error message and stack trace?
- [ ] Have I checked the network tab, logs, and environment variables?
- [ ] Can I shrink it to a minimal reproducible example?

## Wrapping up

Most of these bugs come from a handful of root causes: misunderstanding where a rule is enforced (CORS), hidden cost (N+1), async behavior, and configuration hygiene. Learning to recognize the *category* of a problem speeds up debugging a lot.

**Which of these has cost you the most time? Share your worst debugging story in the comments.** 👇
Enter fullscreen mode Exit fullscreen mode

Top comments (1)

Collapse
 
officialmailkr profile image
오피셜메일 •

비동기 forEach를 순차 처리와 Promise.all로 나눠 설명한 부분이 좋네요. 외부 API나 DB 쓰기 작업이라면 Promise.all도 동시에 요청을 너무 많이 보낼 수 있으니, 동시 실행 수 제한과 부분 실패 재시도 기준까지 함께 두면 운영 중 디버깅에 더 도움이 될 것 같습니다.