usebruno/bruno · error · Error

HeaderList is read-only (response headers cannot be modified

Error message

HeaderList is read-only (response headers cannot be modified)

What it means

Thrown by HeaderList write methods (add, upsert, remove, clear, repopulate, populate, assimilate) when the HeaderList instance is in read-only mode. The #assertWritable guard at header-list.js:121-124 checks the private #writable flag, which is set to false for response header lists. Response headers are immutable snapshots; only request headers are writable.

Source

Thrown at packages/bruno-js/src/header-list.js:123

        }
      });
      this.#req = source;
    } else {
      // Static read-only mode — snapshot of response headers
      const rawHeaders = (source && source.headers) || {};
      super({
        keyProperty: 'key',
        valueProperty: 'value',
        items: Object.entries(rawHeaders).map(([key, value]) => ({ key, value }))
      });
      this.#req = null;
    }
    this.#writable = writable;
  }

  #assertWritable() {
    if (!this.#writable) {
      throw new Error('HeaderList is read-only (response headers cannot be modified)');
    }
  }

  // ── Case-insensitive key helpers ──────────────────────────────────────

  /**
   * Case-insensitive string comparison.
   * @param {string} a
   * @param {string} b
   * @returns {boolean}
   */
  static #ciEquals(a, b) {
    return typeof a === 'string' && typeof b === 'string'
      ? a.toLowerCase() === b.toLowerCase()
      : a === b;
  }

  /**

View on GitHub (pinned to 9bdd81c7bd)

Solutions

  1. Modify request headers instead: use req.headerList.add() / req.setHeader() for outgoing requests.
  2. If you need to transform response headers for assertions, copy them to a plain object first instead of mutating the HeaderList.
  3. Check writability before writing if unsure: if the list is from a response, treat it as read-only.

Example fix

// before (post-response script)
res.headerList.add('X-Custom', 'value'); // throws - response headers are read-only

// after (pre-request script)
req.headerList.add('X-Custom', 'value'); // correct - request headers are writable
Defensive patterns

Strategy: validation

Validate before calling

// Check if you are working with request or response headers
// Response header lists are read-only; request header lists are writable.
// In scripts, always write to req.headerList, never res.headerList.
// No runtime API exposes the writable flag; the rule is: response = read-only.
if (source === 'request') {
  req.headerList.add('X-Custom', 'value'); // safe
} else {
  // copy response headers to a plain object for inspection instead
  const headersCopy = { ...res.headerList.toObject() };
}

Try / catch

try {
  headerList.add(key, value);
} catch (e) {
  if (e.message.includes('read-only')) {
    console.error('Cannot modify response headers; they are immutable snapshots');
  }
}

Prevention

When it happens

Trigger: Calling res.getHeaderList().add('X-Custom', 'value') or any write method on res.headers / res.headerList. The HeaderList for responses is constructed with writable=false at header-list.js:118, so add/upsert/remove/clear all invoke #assertWritable and throw.

Common situations: Confusing request headers (writable) with response headers (read-only) and trying to modify the response header list. Attempting to set a header on the response in a post-response script. Using the same code path for req and res header lists without checking writability.

Related errors


AI-assisted analysis of usebruno/bruno@9bdd81c7bd (2026-08-13). Data as JSON: /api/errors/73adb9ca7875d170. Report an issue: GitHub.