{"record":{"id":"930b52e22e71a486","repo":"grafana/k6","slug":"unmarshaling-wait-for-load-state-q-w","errorCode":null,"errorMessage":"unmarshaling wait for load state %q: %w","messagePattern":"unmarshaling wait for load state %q: %w","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/js/modules/k6/browser/common/frame.go","lineNumber":2040,"sourceCode":"\t\treturn nil, nil //nolint:nilnil\n\t}\n\n\treturn result, nil\n}\n\n// WaitForLoadState waits for the given load state to be reached.\n// This will unblock if that lifecycle event has already been received.\nfunc (f *Frame) WaitForLoadState(state string, popts *FrameWaitForLoadStateOptions) error {\n\tf.log.Debugf(\"Frame:WaitForLoadState\", \"fid:%s furl:%q state:%s\", f.ID(), f.URL(), state)\n\tdefer f.log.Debugf(\"Frame:WaitForLoadState:return\", \"fid:%s furl:%q state:%s\", f.ID(), f.URL(), state)\n\n\ttimeoutCtx, timeoutCancel := context.WithTimeout(f.ctx, popts.Timeout)\n\tdefer timeoutCancel()\n\n\twaitUntil := LifecycleEventLoad\n\tif state != \"\" {\n\t\tif err := waitUntil.UnmarshalText([]byte(state)); err != nil {\n\t\t\treturn fmt.Errorf(\"unmarshaling wait for load state %q: %w\", state, err)\n\t\t}\n\t}\n\n\tlifecycleEvent, lifecycleEventCancel := createWaitForEventPredicateHandler(\n\t\ttimeoutCtx,\n\t\tf,\n\t\t[]string{EventFrameAddLifecycle},\n\t\tfunc(data any) bool {\n\t\t\tif le, ok := data.(FrameLifecycleEvent); ok {\n\t\t\t\treturn le.Event == waitUntil\n\t\t\t}\n\t\t\treturn false\n\t\t})\n\tdefer lifecycleEventCancel()\n\n\tif f.hasLifecycleEventFired(waitUntil) {\n\t\treturn nil\n\t}","sourceCodeStart":2022,"sourceCodeEnd":2058,"githubUrl":"https://github.com/grafana/k6/blob/93accf6570dcd306ca5e99cc44c393ee3797761b/internal/js/modules/k6/browser/common/frame.go#L2022-L2058","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Use exactly one of: 'load', 'domcontentloaded', 'networkidle' (lowercase, no spaces)","If the state comes from configuration, validate it against the allowed set before passing it"],"exampleFix":"// before\npage.waitForLoadState('network idle');\n\n// after\npage.waitForLoadState('networkidle');","handlingStrategy":"validation","validationCode":"const STATES = ['load', 'domcontentloaded', 'networkidle'];\nfunction assertLoadState(state) {\n  if (!STATES.includes(state)) throw new Error(`invalid state ${state}; use ${STATES.join('|')}`);\n}\nassertLoadState(cfg.state);","typeGuard":"function isValidLoadState(s) {\n  return s === '' || ['load', 'domcontentloaded', 'networkidle'].includes(s);\n}","tryCatchPattern":null,"preventionTips":["Validate state strings at config load time, not at call time","Keep lifecycle constants in one shared object in the test suite"],"tags":["browser","wait-for-load-state","validation","lifecycle"],"backgroundTag":null,"analyzedSha":"93accf6570dcd306ca5e99cc44c393ee3797761b","analyzedAt":"2026-08-15T21:23:27.118Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}