{"record":{"id":"78dc6d3892c6c0c7","repo":"denoland/deno","slug":"request-method-must-be-get","errorCode":null,"errorMessage":"Request method must be GET","messagePattern":"Request method must be GET","errorType":"validation","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"ext/cache/01_cache.js","lineNumber":154,"sourceCode":"    response = webidl.converters[\"Response\"](response, prefix, \"Argument 2\");\n    // Step 1.\n    let innerRequest = null;\n    // Step 2.\n    if (ObjectPrototypeIsPrototypeOf(RequestPrototype, request)) {\n      innerRequest = toInnerRequest(request);\n    } else {\n      // Step 3.\n      innerRequest = toInnerRequest(new Request(request));\n    }\n    // Step 4.\n    const reqUrl = new URL(innerRequest.url());\n    if (reqUrl.protocol !== \"http:\" && reqUrl.protocol !== \"https:\") {\n      throw new TypeError(\n        `Request url protocol must be 'http:' or 'https:': received '${reqUrl.protocol}'`,\n      );\n    }\n    if (innerRequest.method !== \"GET\") {\n      throw new TypeError(\"Request method must be GET\");\n    }\n    // Step 5.\n    const innerResponse = toInnerResponse(response);\n    // Step 6.\n    if (innerResponse.status === 206) {\n      throw new TypeError(\"Response status must not be 206\");\n    }\n    // Step 7.\n    const varyHeader = getHeader(innerResponse.headerList, \"vary\");\n    if (varyHeader) {\n      const fieldValues = StringPrototypeSplit(varyHeader, \",\");\n      for (let i = 0; i < fieldValues.length; ++i) {\n        const field = fieldValues[i];\n        if (StringPrototypeTrim(field) === \"*\") {\n          throw new TypeError(\"Vary header must not contain '*'\");\n        }\n      }\n    }","sourceCodeStart":136,"sourceCodeEnd":172,"githubUrl":"https://github.com/denoland/deno/blob/89f33cbef296a2b287f323d42de54c871fa69c77/ext/cache/01_cache.js#L136-L172","documentation":"Step 4 of Cache.put(): only GET requests may be stored, because cache matching is defined only for GET. `innerRequest.method !== 'GET'` throws this TypeError.","triggerScenarios":"cache.put(new Request(url, { method: 'POST' }), response) — any non-GET method, including POST, PUT, and HEAD.","commonSituations":"Saving POST/PUT responses for offline replay; fetch-interception code that forwards the original request method into a cache.put call.","solutions":["Guard the call: if (request.method !== 'GET') skip cache.put.","Store POST responses yourself (KV/SQLite) keyed by URL plus body hash.","When only the payload matters, construct a GET Request for the same URL and cache that."],"exampleFix":"// before\nawait cache.put(req, res); // req.method === 'POST'\n// after\nif (req.method === 'GET') {\n  await cache.put(req, res);\n} else {\n  await kv.set(['post', req.url], await res.clone().text());\n}","handlingStrategy":"validation","validationCode":"const req = input instanceof Request ? input : new Request(input);\nif (req.method === 'GET') {\n  await cache.put(req, response);\n}","typeGuard":null,"tryCatchPattern":"try { await cache.put(req, res); } catch (e) { if (e instanceof TypeError && /GET/.test(e.message)) { /* store elsewhere */ } else throw e; }","preventionTips":["Check request.method before every cache.put in shared/interceptor code.","Remember the whole Cache API (put and match) is GET-only by spec."],"tags":["cache","http-method","service-worker"],"backgroundTag":null,"analyzedSha":"89f33cbef296a2b287f323d42de54c871fa69c77","analyzedAt":"2026-08-16T07:54:21.310Z","schemaVersion":2},"datasetVersion":"2026-08-16T08:17:34.114Z"}