Skip to content

Crash in _processActions: string rate-limit error causes TypeError on err.response.data #12

@glob444

Description

@glob444

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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions