grafana/k6 · error

newResolver(%+v): %w

Error message

newResolver(%+v): %w

What it means

Thrown while creating a browser NetworkManager (i.e., when a new browser context/page initializes networking) if the DNS resolver cannot be built from the test's dns options. The only real failure path is an invalid dns.ttl string, which surfaces as newResolver(...): parsing TTL: invalid DNS TTL: <value> in the wrapped chain.

Source

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

	wg sync.WaitGroup
}

// NewNetworkManager creates a new network manager.
func NewNetworkManager(
	ctx context.Context,
	customMetrics *k6ext.CustomMetrics,
	s session,
	fm *FrameManager,
	parent *NetworkManager,
	ei eventInterceptor,
) (*NetworkManager, error) {
	vu := k6ext.GetVU(ctx)
	state := vu.State()

	resolver, err := newResolver(state.Options.DNS)
	if err != nil {
		return nil, fmt.Errorf("newResolver(%+v): %w", state.Options.DNS, err)
	}

	m := NetworkManager{
		BaseEventEmitter: NewBaseEventEmitter(ctx),
		ctx:              ctx,
		// TODO: Pass an internal logger instead of basing it on k6's logger?
		// See https://go.k6.io/k6/v2/js/modules/k6/browser/issues/54
		logger:                        log.New(state.Logger, GetIterationID(ctx)),
		session:                       s,
		parent:                        parent,
		frameManager:                  fm,
		resolver:                      resolver,
		vu:                            vu,
		customMetrics:                 customMetrics,
		reqIDToRequest:                make(map[network.RequestID]*Request),
		reqIDToRequestWillBeSentEvent: make(map[network.RequestID]*network.EventRequestWillBeSent),
		reqIDToRequestPausedEvent:     make(map[network.RequestID]*fetch.EventRequestPaused),
		extraInfoTracker:              newExtraInfoTracker(),

View on GitHub (pinned to 93accf6570)

Solutions

  1. Set dns.ttl to a single valid value: '0', 'inf', or one duration like '1m'
  2. Remove or override the dns block for browser scenarios if HTTP-only options leak in via --config or exported options
  3. Validate the duration syntax: number plus unit s/m/h (no 'hr', no negatives, no lists)
  4. When both HTTP and browser tests share options, keep ttl single-valued so both stacks accept it

Example fix

// before (k6 options, valid for HTTP module but breaks browser module)
export const options = { dns: { ttl: '60s,5m', select: 'first' } };

// after
export const options = { dns: { ttl: '60s', select: 'first' } };
Defensive patterns

Strategy: validation

Validate before calling

// fail fast at init instead of at page creation
const TTL = __ENV.K6_DNS_TTL || '1m';
if (!/^(0|inf|\d+(\.\d+)?(ms|s|m|h))$/.test(TTL)) {
  throw new Error(`invalid dns.ttl: ${TTL}`);
}
export const options = { dns: { ttl: TTL } };

Type guard

function isValidTtl(v) {
  return v === '0' || v === 'inf' || v === '' || /^\d+(\.\d+)?(ms|s|m|h)$/.test(v);
}

Prevention

When it happens

Trigger: Creating a page/context while k6 options contain dns.ttl that parseTTL cannot parse: anything other than '0', 'inf', empty, or a single valid duration (e.g. 'abc', '-1m', or a comma list like '60s,5m' that k6's HTTP stack accepts but the browser module does not split).

Common situations: Reusing an existing k6 HTTP options block with a comma-separated TTL list in a browser test; typo'd duration units ('1hr' instead of '1h'); negative TTL values; environment-specific options files injected via --config.

Related errors


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