grafana/k6 · error

exported 'teardown' must be a function

Error message

exported 'teardown' must be a function

What it means

Same export scan as `setup`: k6 requires an export named `teardown` to be a callable function so it can run it once after all iterations. A non-function teardown binding is rejected during bundle loading (bundle.go:227).

Source

Thrown at internal/js/bundle.go:227

				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
}

func beautifyOptionsJSONUnmarshalError(data []byte, err error) error {
	unmarshalTypError := new(json.UnmarshalTypeError)

View on GitHub (pinned to 93accf6570)

Solutions

  1. Declare it as a function: `export function teardown() { ... }`
  2. To conditionally skip teardown, remove the export or guard inside the function instead of exporting a boolean
  3. Rename unrelated data exports away from the reserved name

Example fix

// before
export const teardown = false;

// after
export function teardown(data) { if (!data) return; /* cleanup */ }
Defensive patterns

Strategy: type-guard

Validate before calling

if (typeof teardown !== 'undefined' && typeof teardown !== 'function') { throw new Error('teardown export must be a function'); }

Type guard

const isValidTeardown = (v) => v === undefined || typeof v === 'function';

Prevention

When it happens

Trigger: `export const teardown = true`, `export let teardown = {}`, or importing and re-exporting a non-function value under the name `teardown` in the entry script.

Common situations: Feature-flag objects like `export const teardown = false` meant to disable teardown; refactors that changed teardown into data; typos such as `teardownFn`.

Related errors


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