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
- If the stop was intended, treat exit code 103 as a clean stop in CI (e.g. 'k6 run script.js || test $? -eq 103')
- Find the caller: check what has access to the REST API address and any cloud UI activity for this run
- Bind the REST API to loopback only: run with --address 127.0.0.1:6565 so remote clients cannot stop the test
- 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
- Never bind the k6 REST API to 0.0.0.0 in shared networks; keep it on 127.0.0.1
- Audit CI scripts and dashboards for anything PATCHing /v1/status with stopped:true
- Document exit code 103 (ScriptStoppedFromRESTAPI) in team runbooks so operators recognize intentional stops
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.