{"record":{"id":"6e530686c460e682","repo":"grafana/k6","slug":"103","errorCode":"103","errorMessage":"test run stopped from REST API","messagePattern":"test run stopped from REST API","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"error","filePath":"api/v1/status_routes.go","lineNumber":46,"sourceCode":"\tbody, err := io.ReadAll(r.Body)\n\tif err != nil {\n\t\tapiError(rw, \"Couldn't read request\", err.Error(), http.StatusBadRequest)\n\t\treturn\n\t}\n\n\tvar statusEnvelop StatusJSONAPI\n\tif err = json.Unmarshal(body, &statusEnvelop); err != nil {\n\t\tapiError(rw, \"Invalid data\", err.Error(), http.StatusBadRequest)\n\t\treturn\n\t}\n\n\tstatus := statusEnvelop.Status()\n\n\tif status.Stopped { //nolint:nestif\n\t\texecution.AbortTestRun(\n\t\t\tcs.RunCtx,\n\t\t\terrext.WithAbortReasonIfNone(\n\t\t\t\terrext.WithExitCodeIfNone(fmt.Errorf(\"test run stopped from REST API\"), exitcodes.ScriptStoppedFromRESTAPI),\n\t\t\t\terrext.AbortedByUser,\n\t\t\t),\n\t\t)\n\t} else {\n\t\tif status.Paused.Valid {\n\t\t\tif err = cs.Scheduler.SetPaused(status.Paused.Bool); err != nil {\n\t\t\t\tapiError(rw, \"Pause error\", err.Error(), http.StatusInternalServerError)\n\t\t\t\treturn\n\t\t\t}\n\t\t}\n\n\t\tif status.VUsMax.Valid || status.VUs.Valid {\n\t\t\tapiError(rw, \"Execution config error\",\n\t\t\t\t\"live VU configuration updates are not supported\", http.StatusInternalServerError)\n\t\t\treturn\n\t\t}\n\t}\n","sourceCodeStart":28,"sourceCodeEnd":64,"githubUrl":"https://github.com/grafana/k6/blob/93accf6570dcd306ca5e99cc44c393ee3797761b/api/v1/status_routes.go#L28-L64","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":"# before - CI treats any non-zero exit as failure\nk6 cloud run --local-execution script.js\n\n# after - accept the intentional-stop exit code\nk6 cloud run --local-execution script.js\nstatus=$?\nif [ $status -ne 0 ] && [ $status -ne 103 ]; then exit $status; fi","handlingStrategy":"try-catch","validationCode":"# optionally gate remote control: bind the REST API to loopback so only local tools can stop the run\nk6 run --address 127.0.0.1:6565 script.js","typeGuard":null,"tryCatchPattern":"# CI wrapper: exit 103 is the documented intentional stop, not a failure\nk6 cloud run --local-execution script.js\nstatus=$?\ncase $status in\n  0) ;;\n  103) echo 'test stopped via REST API; treating as clean stop' ;;\n  *) exit $status ;;\nesac","preventionTips":["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"],"tags":["rest-api","lifecycle","exit-code","abort","cloud"],"backgroundTag":null,"analyzedSha":"93accf6570dcd306ca5e99cc44c393ee3797761b","analyzedAt":"2026-08-15T21:23:27.118Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}