#3359·newman

--timeout has no effect on collections using setNextRequest()

Author: anubhavaronCreated May 8, 2026Updated May 8, 2026

Summary

newman --timeout (and the equivalent programmatic newman.run({ timeout }), which maps to postman-runtime's timeout.global) does not abort a run when the collection uses pm.execution.setNextRequest(<self>) to poll.

The runtime correctly fires its done(err) callback at the deadline with err.message = 'callback timed out', but does not halt its internal request queue. Newman keeps making HTTP requests indefinitely after telling the user the run is "done" — only an external SIGTERM stops it.

This caused a CI step in our pipeline to run for several hours before the agent's own step timeout killed it.

Environment

newman 6.2.1
postman-runtime 7.39.1
Node.js 22.21.0
OS Windows 11 (also reproduced on Ubuntu 22.04)

Minimal reproduction

repro.postman_collection.json — a 1-request collection that re-queues itself:

json
{
  "info": { "name": "repro", "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json" },
  "item": [{
    "name": "Poll Self",
    "request": { "method": "GET", "url": "https://postman-echo.com/get" },
    "event": [{
      "listen": "test",
      "script": { "type": "text/javascript", "exec": [
        "var n = Number(pm.variables.get('iter') || 0) + 1;",
        "pm.variables.set('iter', n);",
        "if (!pm.variables.get('startedAt')) { pm.variables.set('startedAt', Date.now()); }",
        "console.log('iteration', n, 'elapsedMs', Date.now() - Number(pm.variables.get('startedAt')));",
        "pm.execution.setNextRequest(pm.info.requestName);"
      ]}
    }]
  }]
}
bash
npm install [email protected]
newman run repro.postman_collection.json --timeout 10000

Result: ran for 60 s, completed 197 iterations, never aborted. Killed externally. stderr received error: callback timed out from the runtime, yet iterations continued unabated.

Smoking gun (programmatic API)

This proves the callback fires on time but the runtime keeps the event loop busy:

javascript
const newman = require('newman');
const collection = require('./repro.postman_collection.json');
const t0 = Date.now();
const elapsed = () => ((Date.now() - t0) / 1000).toFixed(1);

let firedAt = null;
newman.run({ collection, timeout: 5000, reporters: [] }, (err) => {
  firedAt = elapsed();
  console.log(`[t=${firedAt}s] callback fired. err: ${err && err.message}`);
  // intentionally NOT calling process.exit()
});

setInterval(() => {
  if (firedAt) console.log(`[t=${elapsed()}s] WATCHDOG: callback fired at ${firedAt}s, but event loop still busy.`);
}, 2000);

setTimeout(() => { console.log(`[t=${elapsed()}s] HARD KILL`); process.exit(99); }, 25000);

Output:

[t=5.0s] callback fired. err: callback timed out
[t=6.0s]  WATCHDOG: callback fired at 5.0s, but event loop still busy.
[t=8.0s]  WATCHDOG: callback fired at 5.0s, but event loop still busy.
...
[t=24.1s] WATCHDOG: callback fired at 5.0s, but event loop still busy.
[t=25.0s] HARD KILL

done(err) fires at exactly the deadline, but the runtime keeps dispatching setNextRequest iterations for the next 20 s until we hard-kill the process.

Expected behavior

When timeout.global fires, the runtime should also abort its internal request queue so no further requests are dispatched and the event loop can drain.

Actual behavior

Only the done callback fires. The request queue keeps running. The user-facing --timeout flag is effectively a no-op for setNextRequest polling collections.

Impact

Real production hazard for CI workflows that poll an async backend with setNextRequest. If the upstream service returns a non-terminal status indefinitely, the documented --timeout flag provides a false sense of safety — only an external process killer ends the run.