{
  "slug": "k6-group-preserves-metric-context-across-asynchronous-calls-723b94082eb6",
  "title": "k6 group() preserves metric context across asynchronous calls",
  "tools": [
    "k6"
  ],
  "tags": [
    "agent"
  ],
  "introduced_at": "2026-09-21T15:17:03.000Z",
  "announced_at": "2026-09-21T15:17:03.000Z",
  "effective_at": null,
  "date_basis": "source-publication",
  "status": "unknown",
  "how": {
    "incantation": "When an asynchronous test flow needs requests and checks to remain in one group across `await`, run it with the experimental `async-metric-context` feature and use an async `group()` callback. `group_duration` then measures until the callback’s returned promise settles.",
    "examples": [
      "k6 run --features async-metric-context <script.js>",
      "import { check, group } from 'k6';\nimport http from 'k6/http';\n\nexport default async function () {\n  await group('browse', async () => {\n    const response = await http.asyncRequest('GET', 'https://test.k6.io/');\n    check(response, { 'page loaded': (r) => r.status === 200 });\n    await http.asyncRequest('GET', 'https://test.k6.io/contacts.php');\n  });\n}"
    ],
    "gotchas": [
      "Version: v2.3.0",
      "Availability: experimental; enable the `async-metric-context` feature",
      "--features async-metric-context: Enables the experimental feature that permits async `group()` callbacks and propagates metric tags and metadata to asynchronous work. Required to use async callbacks in `group()`; the docs also allow enabling it with `K6_FEATURES=async-metric-context`.",
      "group(name, fn): name (required): String name of the group.",
      "group(name, fn): fn (required): Function containing the group body; with the feature enabled it may be async or return a Promise-like value.",
      "http.asyncRequest(method, url): method (required): Uppercase HTTP method, such as `GET`.",
      "http.asyncRequest(method, url): url (required): HTTP request URL.",
      "Prerequisite: Enable the experimental, opt-in `async-metric-context` feature using `--features async-metric-context` or `K6_FEATURES=async-metric-context`.",
      "Changes inside a group or callback stay local to that work and its asynchronous descendants instead of leaking into unrelated work.",
      "Custom tags and metadata are preserved across promises, timer callbacks, `k6/websockets` listeners, and gRPC stream listeners."
    ]
  },
  "why_it_matters": "When debugging an asynchronous test flow, keep its requests and checks grouped across awaited calls.",
  "before": "`group()` rejected async functions by default, and promise callbacks could lose the group tag.",
  "sources": [
    "https://github.com/grafana/k6/releases/tag/v2.3.0",
    "https://grafana.com/docs/k6/latest/javascript-api/k6/group/",
    "https://grafana.com/docs/k6/latest/javascript-api/k6-http/"
  ],
  "rank": 0.96033,
  "judge": {
    "publish": true,
    "judge_model": "codex-cli/gpt-6-luna+typesafe/jev-1.13.0",
    "prompt_version": "extract-v7+enrich-v2+judge-v2x3+jev-publish-v1"
  },
  "review_state": "approved",
  "provenance": {
    "run_id": "wave2a-20261017",
    "verdict_id": "wave2a-20261017:wave2a-20261017-65a244af489b5976-2:gate",
    "evidence_hash": "dba6ea361338a6ce929886692010d6448197e9e669546fe9ff9e6f7cea7e9e36"
  },
  "review": {
    "draft_hash": "219d55e21815e4200291f4d86a13301ee40aa69154c1e8366f9f2396954ab566",
    "reviewer": "publication-gate",
    "reviewed_at": "2026-10-07T00:00:00.000Z",
    "decision": "wave2a-20261017:gate",
    "reason": "3 of 3 judge runs approved with p_yes >= 0.9 (mean 0.96 >= 0.9; 2 needed) and Jev gave 0.64 (>= 0.6 needed)."
  }
}
