grafana/k6 · error

fail to abort request (id: %s): %w

Error message

fail to abort request (id: %s): %w

What it means

The CDP command Fetch.failRequest returned an error while trying to abort a request, and the error was not context.Canceled (which is deliberately swallowed as debug noise). The interception could not be delivered — usually because the request/target no longer exists on the browser side.

Source

Thrown at internal/js/modules/k6/browser/common/network_manager.go:925

}

func (m *NetworkManager) AbortRequest(requestID fetch.RequestID, errorReason string) error {
	m.logger.Debugf("NetworkManager:AbortRequest", "aborting request (id: %s, errorReason: %s)",
		requestID, errorReason)
	netErrorReason, ok := m.errorReasons[errorReason]
	if !ok {
		return fmt.Errorf("unknown error code: %s", errorReason)
	}

	action := fetch.FailRequest(requestID, netErrorReason)
	if err := action.Do(cdp.WithExecutor(m.ctx, m.session)); err != nil {
		// Avoid logging as error when context is canceled.
		// Most probably this happens when trying to fail a site's background request
		// while the iteration is ending and therefore the browser context is being closed.
		if errors.Is(err, context.Canceled) {
			m.logger.Debug("NetworkManager:AbortRequest", "context canceled interrupting request")
		} else {
			return fmt.Errorf("fail to abort request (id: %s): %w", requestID, err)
		}
	}

	return nil
}

func (m *NetworkManager) ContinueRequest(
	requestID fetch.RequestID,
	opts ContinueOptions,
	originalHeaders []HTTPHeader,
) error {
	m.logger.Debugf("NetworkManager:ContinueRequest", "continuing request (id: %s)", requestID)
	action := fetch.ContinueRequest(requestID)

	if len(opts.Headers) > 0 {
		action = action.WithHeaders(toFetchHeaders(opts.Headers))
	}
	if opts.URL != "" {

View on GitHub (pinned to 93accf6570)

Solutions

  1. Abort early in the handler — before any await that can let navigation proceed
  2. Only handle each intercepted request once (abort XOR continue XOR fulfill)
  3. If it only occurs at iteration end, it is teardown noise: stop aborting once the iteration is ending, or catch and ignore at the script level if acceptable for your assertions
  4. Reduce the race by unroute()-ing before page.close()

Example fix

// before
page.route('**/*', async r => {
  await somethingSlow();
  await r.abort('aborted'); // request may be gone by now
});

// after
page.route('**/*', r => r.abort('aborted')); // decide and abort immediately
Defensive patterns

Strategy: try-catch

Validate before calling

if (page.isClosed()) { /* skip aborting: request lifecycle already over */ }

Try / catch

try {
  await route.abort('aborted');
} catch (e) {
  if (/fail to abort request/.test(String(e))) return; // stale request; nothing to abort
  throw e;
}

Prevention

When it happens

Trigger: route.abort(reason) executed after the page navigated away or the target was destroyed, so the fetch.RequestID is stale; aborting a background request (analytics, long-poll, service worker fetch) while the browser context is closing but the context wasn't canceled yet; double-handling the same route (abort twice).

Common situations: Aborting third-party/background requests at end-of-iteration; handlers racing page.close(); SPA sites that re-issue requests during navigation so the handler's request is already gone.

Related errors


AI-assisted analysis of grafana/k6@93accf6570 (2026-08-15). Data as JSON: /api/errors/3799a2da74e41148. Report an issue: GitHub.