denoland/deno · error · TypeError
Method is forbidden
Error message
Method is forbidden
What it means
After normalization to uppercase, the methods CONNECT, TRACE, and TRACK hit the forbidden branch of validateAndNormalizeMethod and throw TypeError 'Method is forbidden', as required by the Fetch spec — these verbs cannot be issued from web-platform fetch. TRACK is rejected alongside TRACE for historical IE-era reasons.
Source
Thrown at ext/fetch/23_request.js:287
* @returns {string}
*/
function validateAndNormalizeMethod(m) {
if (RegExpPrototypeExec(HTTP_TOKEN_CODE_POINT_RE, m) === null) {
throw new TypeError("Method is not valid");
}
const upperCase = StringPrototypeToUpperCase(m);
switch (upperCase) {
case "DELETE":
case "GET":
case "HEAD":
case "OPTIONS":
case "POST":
case "PUT":
return upperCase;
case "CONNECT":
case "TRACE":
case "TRACK":
throw new TypeError("Method is forbidden");
}
return m;
}
class Request {
/** @type {InnerRequest} */
[_request];
/** @type {Headers} */
[_headersCache];
[_getHeaders];
[_headersGuard];
[_signalCache];
[_url];
[_method];
/** @type {Headers} */
get [_headers]() {
if (this[_headersCache] === undefined) {View on GitHub (pinned to 89f33cbef2)
Solutions
- Use a different HTTP method; if you need TRACE/CONNECT semantics, use a lower-level TCP/TLS client instead of fetch
- When forwarding inbound methods, filter out CONNECT/TRACE/TRACK (reply 405) before constructing the outgoing Request
- Map the operation onto a safe custom token method like 'X-Trace' if server and client are both yours
Example fix
// before
const method = inbound.method; // could be 'TRACE'
await fetch(target, { method });
// after
const FORBIDDEN = new Set(['CONNECT', 'TRACE', 'TRACK']);
const method = inbound.method.toUpperCase();
if (FORBIDDEN.has(method)) return new Response(null, { status: 405 });
await fetch(target, { method }); Defensive patterns
Strategy: type-guard
Validate before calling
const FORBIDDEN = new Set(['CONNECT', 'TRACE', 'TRACK']);
function safeMethod(m) {
const upper = String(m).toUpperCase();
if (FORBIDDEN.has(upper)) throw new Error(`forbidden method: ${upper}`);
return upper;
} Type guard
/** @param {string} m */
function isAllowedFetchMethod(m) {
const u = m.toUpperCase();
return /^[!#$%&'*+.^_`|~0-9A-Za-z-]+$/.test(m) && !['CONNECT', 'TRACE', 'TRACK'].includes(u);
} Prevention
- Filter CONNECT/TRACE/TRACK out of forwarded methods (405)
- Do not expose arbitrary client-supplied verbs to fetch
- Use raw TCP/TLS sockets, not fetch, if TRACE/CONNECT behavior is truly required
When it happens
Trigger: fetch(url, { method: 'TRACE' }), new Request(url, { method: 'CONNECT' }), or any casing thereof ('trace', 'Connect'); also proxying a raw method string taken from an inbound request that happened to be TRACE/TRACK.
Common situations: Forwarding arbitrary incoming methods in a proxy/gateway, health-check scripts that try TRACE, or feature flags that map to forbidden verbs.
Understand the failure class
- Authentication and authorization failures — expired tokens, bad credentials, and missing scopes.
Related errors
- Method is not valid
- Request mode 'navigate' is not allowed
- Request with GET/HEAD method cannot have body
- Invalid header: length must be 2, but is ${header.length}
- Cannot read headers: request closed
AI-assisted analysis of denoland/deno@89f33cbef2 (2026-08-16).
Data as JSON: /api/errors/4710b40de5578a4f.
Report an issue: GitHub.