Bug Report
Version
- package.version: 5.15.0
- node: v22.22.2 linux x64
Stack Trace
TypeError: Cannot read properties of undefined (reading 'data')
at /app/tf2autobot/node_modules/@tf2autobot/bptf-listings/index.js:784:52
at /app/tf2autobot/node_modules/async/dist/async.js:3682:19
at wrapper (/app/tf2autobot/node_modules/async/dist/async.js:272:20)
at iterateeCallback (/app/tf2autobot/node_modules/async/dist/async.js:420:21)
at /app/tf2autobot/node_modules/async/dist/async.js:328:20
at /app/tf2autobot/node_modules/async/dist/async.js:3680:17
at /app/tf2autobot/node_modules/@tf2autobot/bptf-listings/index.js:937:28
Bot has been up for 9 minutes.
Fri Mar 27 2026 11:56:46 GMT+0000 (Coordinated Universal Time)
Root Cause
The _processActions error handler at line 782 checks for two types of rate-limit errors:
if (err?.response?.status === 429 || err === 'Rate limited, pausing sending requests to backpack.tf.') {
const s = err.response.data?.message?.match(/in \d+ second/);
The problem: When the second branch matches (the plain string from the global rate limiter), line 784 accesses err.response.data — but a string has no .response property, so err.response is undefined and .data throws TypeError.
The err?.response?.status check on line 782 uses optional chaining, but the .data access on line 784 does NOT. When err is the string 'Rate limited, pausing sending requests to backpack.tf.', it enters the block via the || branch, then crashes.
Additional Issue: _delete error handling leaves _processingActions stuck
There's a related issue in _delete (line 1040-1083): when _delete fails with a non-429 error (400, 500, network timeout), it calls callback(err) which halts async.series. The error handler in _processActions only handles 429 errors — any other error silently drops through without resetting _processingActions to false. This permanently blocks all listing processing (creates, deletes, and getListings refreshes) until the bot restarts.
Suggested Fix
For the crash (line 784): Add a null check before accessing err.response:
if (err?.response?.status === 429 || err === 'Rate limited, pausing sending requests to backpack.tf.') {
const s = err?.response?.data?.message?.match(/in \d+ second/);
const sleepTime = s ? (parseInt(s[0].replace('in ', '').replace(' second', '')) + 1) * 1000 : null;
this.sleepRateLimited = err?.response?.data?.retry_after || sleepTime || 61 * 1000;
For _delete stuck state: Either don't propagate errors from _delete (call callback(null) on non-429 errors), or add a catch-all in the _processActions error handler to always reset _processingActions.
Bug Report
Version
Stack Trace
Root Cause
The
_processActionserror handler at line 782 checks for two types of rate-limit errors:The problem: When the second branch matches (the plain string from the global rate limiter), line 784 accesses
err.response.data— but a string has no.responseproperty, soerr.responseisundefinedand.datathrowsTypeError.The
err?.response?.statuscheck on line 782 uses optional chaining, but the.dataaccess on line 784 does NOT. Whenerris the string'Rate limited, pausing sending requests to backpack.tf.', it enters the block via the||branch, then crashes.Additional Issue:
_deleteerror handling leaves_processingActionsstuckThere's a related issue in
_delete(line 1040-1083): when_deletefails with a non-429 error (400, 500, network timeout), it callscallback(err)which haltsasync.series. The error handler in_processActionsonly handles 429 errors — any other error silently drops through without resetting_processingActionstofalse. This permanently blocks all listing processing (creates, deletes, andgetListingsrefreshes) until the bot restarts.Suggested Fix
For the crash (line 784): Add a null check before accessing
err.response:For
_deletestuck state: Either don't propagate errors from_delete(callcallback(null)on non-429 errors), or add a catch-all in the_processActionserror handler to always reset_processingActions.