Diagnosing k6 Thresholds That Do Not Trigger Expected Pass/Fail Conditions
Learn why k6 thresholds may silently ignore pass/fail conditions and how to diagnose placement, metric collection, and early‑test termination issues.
21 Apr 2026, 06:56 UTC

Recognizable condition
When you run a k6 load test, the test finishes with a "PASS" status even though you expect one or more thresholds to fail (for example, a latency threshold set at 200 ms). The thresholds section in the output shows no entries, or all thresholds are marked as "passed" despite obvious violations in the raw metrics.
Short cause/diagnostic table
| Possible cause | What you might observe |
|---|---|
| Threshold expression contains a syntax error or references an undefined metric | k6 silently ignores the threshold; no threshold lines appear in the terminal or JSON output. |
Threshold defined inside default function or a scenario instead of the options object | Thresholds are not evaluated; you see metric values but no threshold results. |
| The metric used in the threshold is never generated (no HTTP requests, mocked calls, or custom metric not emitted) | Metric value is zero or absent; threshold evaluation has nothing to compare against. |
Test aborts early via exec.interrupt or an uncaught runtime error before the end‑of‑test evaluation phase | Thresholds are skipped; the final summary shows a pass status even though the test stopped prematurely. |
Ordered checks
-
Verify threshold placement and syntax
- Open the test script and locate the
optionsblock. - Ensure each threshold is a string inside
options.thresholds(e.g.,options.thresholds = { 'http_req_duration': ['p(95)<200'] };). - Run the script with verbose console output to see if k6 parses the threshold:
# Run from a terminal with execute permission on the k6 binary k6 run --console-output='verbose' ./my_test.js - Open the test script and locate the
- Check the terminal for a line like
thresholds:followed by each threshold. If the line is missing or showsignore, the threshold was not parsed. - Fix: Correct any typos, ensure metric names match exactly those emitted by k6 (case‑sensitive), and move thresholds out of any function scope into
options. -
Confirm the metric is being collected
- Add a temporary metric print or console log inside the script to verify data:
import { Trend } from 'k6/metrics' const latency = new Trend('http_req_duration'); export default function () { const res = http.get('https://example.com'); latency.add(res.timings.duration); if (__VU === 1 && __ITER === 1) { console.log(`First latency sample: ${res.timings.duration} ms`); } } - Run the test again and look for the printed value or the metric’s output in the summary.
- Fix: If the metric never appears, ensure the test actually performs the action that generates it (e.g., real HTTP requests, not mocked/stubbed calls). Remove any interception that prevents metric emission.
-
Ensure the test runs to completion
- Run the test with a short duration and no intentional interruptions:
k6 run --duration=30s ./my_test.js - Inspect the output for any error stack traces or
exec.interruptcalls. - Fix: Remove early‑exit logic or handle errors so the test reaches the end‑of‑test evaluation phase where thresholds are processed.
Fixes tied to findings
- Syntax / placement error → Move thresholds to
optionsand correct the expression. - Missing metric → Adjust the test script to generate the metric or select an existing one that is emitted.
- Early termination → Eliminate
exec.interruptor uncaught exceptions; let the test finish naturally.
Escalation criteria
If after performing the three ordered checks:
- Thresholds still do not appear in the output,
- Metric collection is confirmed but thresholds remain ignored, and
- The test completes without errors,
then escalate to:
- Checking the k6 version (threshold behavior changed in v0.44.0 when
options.thresholdsbecame mandatory). - Enabling full debug logs with
K6_DEBUG=1to see internal threshold evaluation messages. - Opening a ticket with the k6 maintainers, providing the minimal reproducible script and the verbose log output.
Limitations and practical verification
This guide assumes you are using a recent stable release of k6 (≥ 0.44.0) where thresholds must be defined in options. Older versions may accept thresholds elsewhere, but the behavior differs.
To verify that a fix worked, run the test again and inspect the thresholds section:
k6 run --out json=result.json ./my_test.js
# then examine result.json
jq '.thresholds' result.json
Each threshold object should contain a passed boolean reflecting the expected outcome based on the metric values.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.