anuraghazra / anuraghazra/github-readme-stats

Critical: Uncaught TypeError crashes on network errors due to unsafe err.response access in retryer.js and wakatime.js

Open
#4,510 1 comment 0 reactions 0 assignees View on GitHub
bug
Dominant language
JavaScript
Stars
79.8k
Forks
37.7k
PR merge metrics
No merged PRs in 30d

Description

### Describe the bug

## Bug Description

The application crashes with `TypeError: Cannot read
property 'data' of undefined` when network errors occur
(timeouts, DNS failures, connection refused, etc.) due to
unsafe property access on `err.response` in the error
handling code.

## Affected Files

1. **`src/common/retryer.js:66-69`** (Critical - affects all
GitHub API calls)
2. **`src/fetchers/wakatime.js:24`** (Critical - affects
Wakatime stats fetching)

## Root Cause

When axios encounters network-level errors (ECONNREFUSED,
ETIMEDOUT, ENOTFOUND, etc.), the error object does not
contain a `response` property. The current code attempts to
access `err.response.data` and `err.response.status`
directly without null-safety checks, causing crashes.

### Problematic Code

**src/common/retryer.js:66-69:**
```javascript
} catch (err) {
// ❌ CRASHES if err.response is undefined
const isBadCredential = err.response.data &&
err.response.data.message === "Bad credentials";
const isAccountSuspended =
err.response.data &&
err.response.data.message === "Sorry. Your account was
suspended.";

if (isBadCredential || isAccountSuspended) {
logger.log(`PAT_${retries + 1} Failed`);
retries++;
return retryer(fetcher, variables, retries);
} else {
return err.response; // Returns undefined if
err.response doesn't exist
}
}

src/fetchers/wakatime.js:24:
} catch (err) {
// ❌ CRASHES if err.response is undefined
if (err.response.status < 200 || err.response.status >
299) {
throw new CustomError(
`Could not resolve to a User with the login of
'${username}'`,
"WAKATIME_USER_NOT_FOUND",
);
}
throw err;
}
```

Impact

- Severity: 🔴 HIGH
- User Impact: Complete API endpoint failure with 500 errors
- Frequency: Occurs during network instability, DNS issues,
or GitHub API unavailability
- Scope: Affects all users attempting to generate stats
cards during network issues

Steps to Reproduce

1. Simulate network timeout or connection failure to GitHub
API
2. Attempt to fetch GitHub stats
3. Observe TypeError: Cannot read property 'data' of
undefined crash
4. API returns 500 error instead of graceful error handling

Quick reproduction (for testing):
```
// Simulate network error without response object
const networkError = new Error('ECONNREFUSED');
// networkError.response is undefined
```
Expected Behavior

The application should gracefully handle network errors and
either:
- Retry with the next available token
- Return a user-friendly error message
- Not crash the entire API endpoint

Actual Behavior

Application crashes with unhandled exception, breaking the
API endpoint completely.

Proposed Solution

Use optional chaining (?.) for safe property access:

Fix for src/common/retryer.js:
```
} catch (err) {
// ✅ Safe property access
const isBadCredential = err.response?.data?.message ===
"Bad credentials";
const isAccountSuspended = err.response?.data?.message ===
"Sorry. Your account was suspended.";

if (isBadCredential || isAccountSuspended) {
logger.log(`PAT_${retries + 1} Failed`);
retries++;
return retryer(fetcher, variables, retries);
} else {
// Handle case where err.response doesn't exist
return err.response || { data: { errors: [{ message:
err.message }] } };
}
}
```

Fix for src/fetchers/wakatime.js:
```
} catch (err) {
// ✅ Safe property access with fallback
const status = err.response?.status;
if (status && (status < 200 || status > 299)) {
throw new CustomError(
`Could not resolve to a User with the login of
'${username}'`,
"WAKATIME_USER_NOT_FOUND",
);
}
throw err;
}

Evidence of Inconsistency

Interestingly, api/status/pat-info.js:97 already uses the
correct pattern:
const errorMessage =
err.response?.data?.message?.toLowerCase(); //
```
✅ Correct

This indicates awareness of the issue in newer code, but
older error handlers weren't updated.

Additional Recommendations

1. Add test coverage for network error scenarios in
tests/retryer.test.js
2. Audit all err.response usage across the codebase for
consistency
3. Add ESLint rule to prevent unsafe optional property
access on error objects

Related Code

- Git blame shows lines 66-69 in retryer.js date back to
2020-2023
- Recent commit ba9406e added comments about rate limit
detection but didn't fix the unsafe access

Environment

- Node.js: v22+ (as per package.json engines)
- All deployment environments affected (Vercel, self-hosted)

### Expected behavior

_No response_

### Screenshots / Live demo link

_No response_

### Additional context

_No response_

Contributor guide

Open the contributing guide

Research direction

Start with the catch blocks in src/common/retryer.js:66-69 and src/fetchers/wakatime.js:24, then compare their error handling with api/status/pat-info.js:97. Add coverage for errors without a response object in tests/retryer.test.js and verify network failures no longer cause an uncaught TypeError or a 500 crash.

Written by the indexing model from the issue text.

Assessment

Tech stack
javascript
Domain
api, backend
Issue type
Bug
Difficulty
3/5
Estimated time
1-2 days
Activity status
Stale
Clarity
Clearly specified
Newbie friendliness
52/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.