grafana/k6 · warning

105

105

Error message

test run was aborted because k6 received a '%s' signal

What it means

k6 traps SIGINT and SIGTERM for the duration of a local run. On the first signal it gracefully stops the test, propagates this error (exit code 105, ExternalAbort, abort reason AbortedByUser), and cancels lingering contexts. A second signal triggers the hard-stop path instead. The signal name is included in the message.

Solutions

  1. If you stopped the test intentionally, no fix is needed — this is the expected outcome
  2. In CI, raise the job/step timeout so k6 finishes before the runner sends SIGTERM
  3. For containers/orchestrators, allow a generous graceful termination period before SIGKILL so k6 can flush metrics and the summary
  4. Treat exit code 105 as 'cancelled/aborted by user', not as a test failure, in pipeline result mapping
Defensive patterns

Strategy: try-catch

Try / catch

# distinguish user/system aborts (105) from real failures
k6 run script.js
ec=$?
if [ "$ec" -eq 105 ]; then
  echo "test aborted by SIGINT/SIGTERM — marking job as cancelled" >&2
  exit 0   # or a dedicated 'cancelled' status
fi
exit "$ec"

Prevention

When it happens

Trigger: Ctrl+C in a terminal; CI/container runtimes sending SIGTERM on job timeout or pod eviction; `timeout 60 k6 run ...`; systemd stop; orchestrators signaling the whole process group.

Common situations: Kubernetes pod eviction mid-test; CI step time limits smaller than the scripted duration; shared agents reaping long jobs; accidental double Ctrl+C.

Related errors


AI-assisted analysis of grafana/k6@3fcf5388d7 (2026-08-18). Data as JSON: /api/errors/daa6c7a0a67caed1. Report an issue: GitHub.

Appendix: source

Thrown at internal/cmd/run.go:409

	defer func() {
		logger.Debug("Waiting for metrics processing to finish...")
		close(samples)
		waitOutputsFlushed()
		logger.Debug("Metrics processing finished!")
	}()

	printExecutionDescription(
		c.gs, "local", args[0], "", conf, executionState.ExecutionTuple, executionPlan, outputs,
	)

	// Trap Interrupts, SIGINTs and SIGTERMs.
	// TODO: move upwards, right after runCtx is created
	gracefulStop := func(sig os.Signal) {
		logger.WithField("sig", sig).Debug("Stopping k6 in response to signal...")
		// first abort the test run this way, to propagate the error
		runAbort(errext.WithAbortReasonIfNone(
			errext.WithExitCodeIfNone(
				fmt.Errorf("test run was aborted because k6 received a '%s' signal", sig), exitcodes.ExternalAbort,
			), errext.AbortedByUser,
		))
		lingerCancel() // cancel this context as well, since the user did Ctrl+C
	}
	onHardStop := func(sig os.Signal) {
		logger.WithField("sig", sig).Error("Aborting k6 in response to signal")
		globalCancel() // not that it matters, given that os.Exit() will be called right after
	}
	stopSignalHandling := handleTestAbortSignals(c.gs, gracefulStop, onHardStop)
	defer stopSignalHandling()

	// Initialize the VUs and executors
	stopVUEmission, err := execScheduler.Init(runCtx, samples)
	if err != nil {
		return err
	}
	defer stopVUEmission()

View on GitHub (pinned to 3fcf5388d7)