grafana/k6 · error
exported 'setup' must be a function
Error message
exported 'setup' must be a function
What it means
While scanning the entry module's exports, k6 special-cases the lifecycle names. An export named `setup` that is not a function cannot be invoked once before VU iterations, so the bundle loader rejects it immediately (bundle.go:224).
Source
Thrown at internal/js/bundle.go:224
return
}
dec := json.NewDecoder(bytes.NewReader(data))
dec.DisallowUnknownFields()
if err = dec.Decode(&b.Options); err != nil {
if uerr := json.Unmarshal(data, &b.Options); uerr != nil {
// Beautify the error so we can try to show the user the key and potential value that is failing to parse
uerr = beautifyOptionsJSONUnmarshalError(data, uerr)
err = errext.WithAbortReasonIfNone(
errext.WithExitCodeIfNone(uerr, exitcodes.InvalidConfig),
errext.AbortedByScriptError,
)
return
}
b.preInitState.Logger.WithError(err).Warn("There were unknown fields in the options exported in the script")
err = nil
}
case consts.SetupFn:
err = errors.New("exported 'setup' must be a function")
return
case consts.TeardownFn:
err = errors.New("exported 'teardown' must be a function")
return
}
}
})
<-ch
if err != nil {
return err
}
if len(b.callableExports) == 0 {
return errors.New("no exported functions in script")
}
return nil
}View on GitHub (pinned to 93accf6570)
Solutions
- Declare it as a function: `export function setup() { ... }`
- If the export is data, rename it so it does not collide with the reserved lifecycle name
Example fix
// before
export const setup = { token: 'abc' };
// after
export const config = { token: 'abc' };
export function setup() { return config; } Defensive patterns
Strategy: type-guard
Validate before calling
if (typeof setup !== 'undefined' && typeof setup !== 'function') { throw new Error('setup export must be a function'); } Type guard
const isValidSetup = (v) => v === undefined || typeof v === 'function';
Prevention
- Keep reserved lifecycle names (setup, teardown, default, options, handleSummary) out of data exports
- Lint scripts in CI for `export const setup` / `export const teardown` patterns
- Run `k6 inspect script.js` locally — export-shape errors surface at load time before any traffic
When it happens
Trigger: `export const setup = 'x'`, `export let setup = 42`, or re-exporting a non-function binding named `setup` from the main module; fires during script load, before anything runs.
Common situations: Typos like `export function setups()`; refactors that turned setup into a config object or constant; codegen emitting `export const setup = {...}`.
Related errors
- exported 'teardown' must be a function
- no exported functions in script
- no gRPC connection, you must call connect first
- open() can't be used with an empty filename
- predicate function is not callable
AI-assisted analysis of grafana/k6@93accf6570 (2026-08-15).
Data as JSON: /api/errors/ab9fb0b2530c4caa.
Report an issue: GitHub.