{"record":{"id":"e22f3cefe3d9994d","repo":"grafana/k6","slug":"test-execution-was-already-paused","errorCode":null,"errorMessage":"test execution was already paused","messagePattern":"test execution was already paused","errorType":"http","errorClass":null,"httpStatus":500,"severity":"warning","filePath":"lib/execution.go","lineNumber":409,"sourceCode":"\t\t} else {\n\t\t\t// The test isn't paused or finished, use the current time instead\n\t\t\tendTime = time.Now().UnixNano()\n\t\t}\n\t}\n\n\treturn time.Duration(endTime-startTime) - pausedDuration\n}\n\n// Pause pauses the current execution. It acquires the lock, writes\n// the current timestamp in currentPauseTime, and makes a new\n// channel for resumeNotify.\n// Pause can return an error if the test was already paused.\nfunc (es *ExecutionState) Pause() error {\n\tes.pauseStateLock.Lock()\n\tdefer es.pauseStateLock.Unlock()\n\n\tif !atomic.CompareAndSwapInt64(es.currentPauseTime, 0, time.Now().UnixNano()) {\n\t\treturn errors.New(\"test execution was already paused\")\n\t}\n\tes.resumeNotify = make(chan struct{})\n\treturn nil\n}\n\n// Resume unpauses the test execution. Unless the test wasn't\n// yet started, it calculates the duration between now and\n// the old currentPauseTime and adds it to\n// Resume will emit an error if the test wasn't paused.\nfunc (es *ExecutionState) Resume() error {\n\tes.pauseStateLock.Lock()\n\tdefer es.pauseStateLock.Unlock()\n\n\tcurrentPausedTime := atomic.SwapInt64(es.currentPauseTime, 0)\n\tif currentPausedTime == 0 {\n\t\treturn errors.New(\"test execution wasn't paused\")\n\t}\n","sourceCodeStart":391,"sourceCodeEnd":427,"githubUrl":"https://github.com/grafana/k6/blob/93accf6570dcd306ca5e99cc44c393ee3797761b/lib/execution.go#L391-L427","documentation":"ExecutionState.Pause() pauses the whole test run by CAS-ing currentPauseTime from 0 to now under pauseStateLock; if the CAS fails the test was already paused and the duplicate Pause() returns this error. Pausing freezes iteration timing until Resume() is called.","triggerScenarios":"Calling the REST API 'POST /v1/pause' twice without an intervening /v1/resume, or programmatically calling Pause() twice on the ExecutionState shared by the run.","commonSituations":"Automation/CI scripts that fire pause on a timer without checking state; two operators (or a dashboard and a script) pausing concurrently; retry logic that re-issues pause because the first response was missed.","solutions":["Check status first: GET /v1/status shows paused:true — only pause when it is false","After pausing, resume with POST /v1/resume before pausing again","Make automation idempotent: treat 'already paused' as success instead of re-issuing"],"exampleFix":"# before\nk6 pause   # ... later, without resume\nk6 pause   # exits with error: test execution was already paused\n\n# after\nk6 status | grep -q '\"paused\": true' || k6 pause","handlingStrategy":"validation","validationCode":"# check before pausing\nstatus=$(curl -s http://localhost:6565/v1/status)\necho \"$status\" | grep -q '\"paused\": *false' && curl -sX POST http://localhost:6565/v1/pause || echo 'already paused'","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Poll /v1/status before issuing pause/resume commands","Make orchestration scripts idempotent around pause state","Pair every pause with exactly one resume in automation"],"tags":["execution","pause-resume","rest-api","state"],"backgroundTag":null,"analyzedSha":"93accf6570dcd306ca5e99cc44c393ee3797761b","analyzedAt":"2026-08-15T21:23:27.118Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}