denoland/deno · error · TypeError
Method is not valid
Error message
Method is not valid
What it means
Request's constructor normalizes the method via validateAndNormalizeMethod, which first tests the string against the HTTP token code-point regex (visible ASCII token characters only: A-Z a-z 0-9 and !#$%&'*+-.^_`|~). A method containing spaces, slashes, parentheses, non-ASCII characters, or an empty string fails the regex and throws TypeError "Method is not valid".
Solutions
- Use a plain token method string: GET, POST, or a custom token like PROPFIND
- Trim whitespace and reject empty strings before constructing the Request
- Validate the method against /^[!#$%&'*+.^_`|~0-9A-Za-z-]+$/ in your config loader
Example fix
// before
const method = config.method ?? "";
new Request("https://example.com", { method }); // throws when empty or "GET /x"
// after
const TOKEN_RE = /^[!#$%&'*+.^_`|~0-9A-Za-z-]+$/;
const method = config.method && TOKEN_RE.test(config.method) ? config.method : "GET";
new Request("https://example.com", { method }); Defensive patterns
Strategy: validation
Validate before calling
const HTTP_TOKEN_RE = /^[!#$%&'*+.^_`|~0-9A-Za-z-]+$/;
if (!HTTP_TOKEN_RE.test(method) || method === "") {
throw new Error(`Invalid HTTP method: ${JSON.stringify(method)}`);
}
const req = new Request(url, { method }); Type guard
const HTTP_TOKEN_RE = /^[!#$%&'*+.^_`|~0-9A-Za-z-]+$/;
function isValidHttpMethod(m: unknown): m is string {
return typeof m === "string" && HTTP_TOKEN_RE.test(m);
} Try / catch
try {
new Request(url, { method });
} catch (err) {
if (err instanceof TypeError && err.message === "Method is not valid") {
// sanitize: fall back to a safe default method
new Request(url, { method: "GET" });
} else throw err;
} Prevention
- Validate method strings at the config/API boundary, not at Request construction
- Trim and reject empty strings before use
- Whitelist known methods and treat anything else as custom-but-token-only
When it happens
Trigger: new Request(url, { method: "" }); method: "GET /path"; method: "POST(json)"; method with a trailing newline or any non-token character; methods read from unsanitized config or headers.
Common situations: Building the method from user input or a template string; empty-string defaults from optional config (config.method ?? "" ); method strings transported through systems that append whitespace or CRLF.
Related errors
- Method is forbidden
- Request with GET/HEAD method cannot have body
- Blob URL fetch only supports GET method
- Body already consumed.
- Body is unusable
AI-assisted analysis of denoland/deno@9ad36f7a2c (2026-08-20).
Data as JSON: /api/errors/f635d40c630b3352.
Report an issue: GitHub.
Appendix: source
Thrown at ext/fetch/23_request.js:273
"get": "GET",
"HEAD": "HEAD",
"head": "HEAD",
"OPTIONS": "OPTIONS",
"options": "OPTIONS",
"PATCH": "PATCH",
"POST": "POST",
"post": "POST",
"PUT": "PUT",
"put": "PUT",
};
/**
* @param {string} m
* @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;
}
View on GitHub (pinned to 9ad36f7a2c)