grafana/k6 · error

unmarshaling wait for load state %q: %w

Error message

unmarshaling wait for load state %q: %w

What it means

Thrown by Frame.WaitForLoadState when the state string cannot be parsed into a LifecycleEvent. waitUntil.UnmarshalText only accepts exactly "load", "domcontentloaded", or "networkidle" (see lifecycle.go's lifecycleEventToID map); anything else fails before any waiting starts. It is a deterministic argument-validation error, not a timing problem.

Source

Thrown at internal/js/modules/k6/browser/common/frame.go:2040

		return nil, nil //nolint:nilnil
	}

	return result, nil
}

// WaitForLoadState waits for the given load state to be reached.
// This will unblock if that lifecycle event has already been received.
func (f *Frame) WaitForLoadState(state string, popts *FrameWaitForLoadStateOptions) error {
	f.log.Debugf("Frame:WaitForLoadState", "fid:%s furl:%q state:%s", f.ID(), f.URL(), state)
	defer f.log.Debugf("Frame:WaitForLoadState:return", "fid:%s furl:%q state:%s", f.ID(), f.URL(), state)

	timeoutCtx, timeoutCancel := context.WithTimeout(f.ctx, popts.Timeout)
	defer timeoutCancel()

	waitUntil := LifecycleEventLoad
	if state != "" {
		if err := waitUntil.UnmarshalText([]byte(state)); err != nil {
			return fmt.Errorf("unmarshaling wait for load state %q: %w", state, err)
		}
	}

	lifecycleEvent, lifecycleEventCancel := createWaitForEventPredicateHandler(
		timeoutCtx,
		f,
		[]string{EventFrameAddLifecycle},
		func(data any) bool {
			if le, ok := data.(FrameLifecycleEvent); ok {
				return le.Event == waitUntil
			}
			return false
		})
	defer lifecycleEventCancel()

	if f.hasLifecycleEventFired(waitUntil) {
		return nil
	}

View on GitHub (pinned to 93accf6570)

Solutions

  1. Use exactly one of: 'load', 'domcontentloaded', 'networkidle' (lowercase, no spaces)
  2. If the state comes from configuration, validate it against the allowed set before passing it

Example fix

// before
page.waitForLoadState('network idle');

// after
page.waitForLoadState('networkidle');
Defensive patterns

Strategy: validation

Validate before calling

const STATES = ['load', 'domcontentloaded', 'networkidle'];
function assertLoadState(state) {
  if (!STATES.includes(state)) throw new Error(`invalid state ${state}; use ${STATES.join('|')}`);
}
assertLoadState(cfg.state);

Type guard

function isValidLoadState(s) {
  return s === '' || ['load', 'domcontentloaded', 'networkidle'].includes(s);
}

Prevention

When it happens

Trigger: page.waitForLoadState('loaded'), page.waitForLoadState('Load'), page.waitForLoadState('network idle'), or a state value built from a variable/typo that is not one of the three accepted strings; an empty string is fine (defaults to load), but any other misspelling hits this path.

Common situations: Copy-pasting Playwright examples with informal state names; case mismatches; passing a waitUntil value configured for goto (where the same enum is used) into waitForLoadState without validation.

Related errors


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