grafana/k6 · error

103

103

Error message

test run stopped from REST API

What it means

While k6 runs it exposes a REST API on --address (default localhost:6565). The PATCH /v1/status handler (api/v1/status_routes.go) reads the posted status envelope, and when attributes.stopped is true it calls execution.AbortTestRun with this error, tagged with AbortedByUser and exit code 103 (exitcodes.ScriptStoppedFromRESTAPI, errext/exitcodes/codes.go:31). It is an intentional, externally-requested abort of the test run - the error text simply records who asked for the stop.

Source

Thrown at api/v1/status_routes.go:46

	body, err := io.ReadAll(r.Body)
	if err != nil {
		apiError(rw, "Couldn't read request", err.Error(), http.StatusBadRequest)
		return
	}

	var statusEnvelop StatusJSONAPI
	if err = json.Unmarshal(body, &statusEnvelop); err != nil {
		apiError(rw, "Invalid data", err.Error(), http.StatusBadRequest)
		return
	}

	status := statusEnvelop.Status()

	if status.Stopped { //nolint:nestif
		execution.AbortTestRun(
			cs.RunCtx,
			errext.WithAbortReasonIfNone(
				errext.WithExitCodeIfNone(fmt.Errorf("test run stopped from REST API"), exitcodes.ScriptStoppedFromRESTAPI),
				errext.AbortedByUser,
			),
		)
	} else {
		if status.Paused.Valid {
			if err = cs.Scheduler.SetPaused(status.Paused.Bool); err != nil {
				apiError(rw, "Pause error", err.Error(), http.StatusInternalServerError)
				return
			}
		}

		if status.VUsMax.Valid || status.VUs.Valid {
			apiError(rw, "Execution config error",
				"live VU configuration updates are not supported", http.StatusInternalServerError)
			return
		}
	}

View on GitHub (pinned to 93accf6570)

Solutions

  1. If the stop was intended, treat exit code 103 as a clean stop in CI (e.g. 'k6 run script.js || test $? -eq 103')
  2. Find the caller: check what has access to the REST API address and any cloud UI activity for this run
  3. Bind the REST API to loopback only: run with --address 127.0.0.1:6565 so remote clients cannot stop the test
  4. Do not expose the k6 REST API port in containers/orchestrators without an allowlist

Example fix

# before - CI treats any non-zero exit as failure
k6 cloud run --local-execution script.js

# after - accept the intentional-stop exit code
k6 cloud run --local-execution script.js
status=$?
if [ $status -ne 0 ] && [ $status -ne 103 ]; then exit $status; fi
Defensive patterns

Strategy: try-catch

Validate before calling

# optionally gate remote control: bind the REST API to loopback so only local tools can stop the run
k6 run --address 127.0.0.1:6565 script.js

Try / catch

# CI wrapper: exit 103 is the documented intentional stop, not a failure
k6 cloud run --local-execution script.js
status=$?
case $status in
  0) ;;
  103) echo 'test stopped via REST API; treating as clean stop' ;;
  *) exit $status ;;
esac

Prevention

When it happens

Trigger: Any client sending PATCH /v1/status with body {"data":{"type":"status","attributes":{"stopped":true}}} to the local REST API: the Grafana Cloud k6 UI stopping a linked local-execution run, a CI script, 'k6 stop'-style tooling, or any HTTP client that can reach the bound address.

Common situations: Someone clicked Stop in the cloud UI for a run executing locally; automation or a teammate hit the status endpoint; the REST API port (6565) is reachable by another process or a network scanner because k6 was started with --address 0.0.0.0:6565; a stale curl command in a pipeline.

Related errors


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