{"record":{"id":"5ead4fb8e90be5cd","repo":"grafana/k6","slug":"getting-scenario-information-outside-of-the-vu-con","errorCode":null,"errorMessage":"getting scenario information outside of the VU context is not supported","messagePattern":"getting scenario information outside of the VU context is not supported","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/js/modules/k6/execution/execution.go","lineNumber":74,"sourceCode":"\t\t\tcommon.Throw(rt, err)\n\t\t}\n\t}\n\tdefProp(\"instance\", mi.newInstanceInfo)\n\tdefProp(\"scenario\", mi.newScenarioInfo)\n\tdefProp(\"test\", mi.newTestInfo)\n\tdefProp(\"vu\", mi.newVUInfo)\n\n\tmi.obj = o\n\n\treturn mi\n}\n\n// Exports returns the exports of the execution module.\nfunc (mi *ModuleInstance) Exports() modules.Exports {\n\treturn modules.Exports{Default: mi.obj}\n}\n\nvar errRunInInitContext = errors.New(\"getting scenario information outside of the VU context is not supported\")\n\n// newScenarioInfo returns a sobek.Object with property accessors to retrieve\n// information about the scenario the current VU is running in.\nfunc (mi *ModuleInstance) newScenarioInfo() (*sobek.Object, error) {\n\trt := mi.vu.Runtime()\n\tvuState := mi.vu.State()\n\tif vuState == nil {\n\t\treturn nil, errRunInInitContext\n\t}\n\tgetScenarioState := func() *lib.ScenarioState {\n\t\tss := lib.GetScenarioState(mi.vu.Context())\n\t\tif ss == nil {\n\t\t\tcommon.Throw(rt, errRunInInitContext)\n\t\t}\n\t\treturn ss\n\t}\n\n\tsi := map[string]func() any{","sourceCodeStart":56,"sourceCodeEnd":92,"githubUrl":"https://github.com/grafana/k6/blob/93accf6570dcd306ca5e99cc44c393ee3797761b/internal/js/modules/k6/execution/execution.go#L56-L92","documentation":"The k6/execution module exposes exec.scenario and exec.vu through property accessors that read live VU state (vu.State()). That state only exists while a VU is executing iterations; in the init context (top-level script code) it is nil, so accessing scenario or VU info there throws errRunInInitContext.","triggerScenarios":"Reading exec.scenario.name, exec.vu.idInTest, or exec.instance at the top level of the script; calling a helper that touches exec from setup()/teardown() or other non-iteration phases; using exec during module-scope constant initialization.","commonSituations":"Trying to compute per-scenario thresholds, tags, or config at file scope; logging or branching on scenario name before the default function; sharing a helper between init and VU phases that unconditionally dereferences exec.","solutions":["Move exec.scenario / exec.vu access inside the default exported function (or functions it calls per iteration)","For init-time branching, use the options/scenarios objects from k6/options or the exported options variable instead","Guard shared helpers: only touch exec when running inside an iteration (pass the info in as arguments)"],"exampleFix":"// before (init context -- throws)\nimport exec from 'k6/execution';\nimport { scenario } from 'k6/execution';\nconst tag = `scenario=${exec.scenario.name}`;\n\n// after\nimport exec from 'k6/execution';\nexport default function () {\n  const tag = `scenario=${exec.scenario.name}`;\n  // ...\n}","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"import exec from 'k6/execution';\n\nfunction safeScenarioName() {\n  try {\n    return exec.scenario.name;\n  } catch (e) {\n    if (String(e.message).includes('outside of the VU context')) return 'init';\n    throw e;\n  }\n}","preventionTips":["Treat exec.vu and exec.scenario as iteration-phase-only APIs; never read them at module scope","Pass scenario name into shared helpers as a parameter captured inside the default function","For init-time decisions use the exported options object or k6/options instead"],"tags":["execution","vu-context","init-context","scenario"],"backgroundTag":null,"analyzedSha":"93accf6570dcd306ca5e99cc44c393ee3797761b","analyzedAt":"2026-08-15T21:23:27.118Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}