{"id":"418e4a38d1d87fad","repo":"axios/axios","slug":"err-bad-request","errorCode":"ERR_BAD_REQUEST","errorMessage":"Unsupported protocol ${protocol}:","messagePattern":"Unsupported protocol (.+?):","errorType":"exception","errorClass":"AxiosError","httpStatus":null,"severity":"error","filePath":"lib/adapters/xhr.js","lineNumber":239,"sourceCode":"          reject(!cancel || cancel.type ? new CanceledError(null, config, request) : cancel);\n          request.abort();\n          done();\n          request = null;\n        };\n\n        _config.cancelToken && _config.cancelToken.subscribe(onCanceled);\n        if (_config.signal) {\n          _config.signal.aborted\n            ? onCanceled()\n            : _config.signal.addEventListener('abort', onCanceled);\n        }\n      }\n\n      const protocol = parseProtocol(_config.url);\n\n      if (protocol && !platform.protocols.includes(protocol)) {\n        reject(\n          new AxiosError(\n            'Unsupported protocol ' + protocol + ':',\n            AxiosError.ERR_BAD_REQUEST,\n            config\n          )\n        );\n        done();\n        return;\n      }\n\n      // Send the request\n      request.send(requestData || null);\n    });\n  };\n","sourceCodeStart":221,"sourceCodeEnd":253,"githubUrl":"https://github.com/axios/axios/blob/c3f553c740ebf3dff5e22dae24e9caaafafddd2d/lib/adapters/xhr.js#L221-L253","documentation":"Rejected synchronously (before request.send) by the XHR adapter when the resolved request URL's scheme, parsed by parseProtocol, is not in `platform.protocols` — for the browser platform: http, https, file, blob, url, data. It is a preflight sanity/security check with code ERR_BAD_REQUEST that stops axios from handing arbitrary schemes (ftp:, ws:, chrome-extension:, custom app schemes) to XMLHttpRequest.","triggerScenarios":"axios.get('ftp://host/file'); axios.get('ws://host/socket') — WebSocket URLs don't belong in axios; a baseURL or interceptor producing a URL like 'chrome-extension://...' or a mobile deep-link scheme ('myapp://'); malformed URL construction yielding an accidental scheme, e.g. missing slash making 'localhost:3000/api' parse with protocol 'localhost'.","commonSituations":"String-concatenating baseURL + path and losing the '//' so the port is parsed as a scheme; passing WebSocket endpoints to axios instead of the WebSocket API; browser-extension development using extension:// URLs; env var containing the URL without the https:// prefix.","solutions":["Fix the URL: ensure it starts with http:// or https:// — log the final _config.url (baseURL + url after merge) to see what axios actually received.","Check environment variables/config for a missing scheme (API_URL=api.example.com should be https://api.example.com).","Use the right client for the protocol: WebSocket API for ws://, an FTP library server-side for ftp://.","If constructing URLs dynamically, use the URL constructor (new URL(path, base)) instead of string concatenation."],"exampleFix":"// before — missing scheme, 'localhost' parsed as the protocol\nconst api = axios.create({ baseURL: 'localhost:3000/api' });\n// after\nconst api = axios.create({ baseURL: 'http://localhost:3000/api' });","handlingStrategy":"validation","validationCode":"const SUPPORTED_PROTOCOLS = ['http:', 'https:'];\nfunction assertSupportedUrl(input, base) {\n  const u = new URL(input, base);\n  if (!SUPPORTED_PROTOCOLS.includes(u.protocol)) {\n    throw new Error(`Unsupported protocol: ${u.protocol}`);\n  }\n  return u.href;\n}\nawait axios.get(assertSupportedUrl(userProvidedUrl, location.origin));","typeGuard":"function isHttpUrl(value) {\n  try {\n    const u = new URL(value, typeof location !== 'undefined' ? location.origin : undefined);\n    return u.protocol === 'http:' || u.protocol === 'https:';\n  } catch {\n    return false;\n  }\n}","tryCatchPattern":"try {\n  await axios.get(url);\n} catch (err) {\n  if (axios.isAxiosError(err) && err.code === 'ERR_BAD_REQUEST' && /Unsupported protocol/.test(err.message)) {\n    // URL came from untrusted input — reject it, never coerce the scheme silently\n  }\n  throw err;\n}","preventionTips":["Validate and normalize any user- or API-supplied URL through new URL() with a protocol allowlist before passing it to axios.","Treat this rejection as a security control: it blocks javascript:, data:, file: and similar schemes — don't work around it.","Use baseURL on your axios instance so relative paths can never smuggle in an unexpected scheme.","Add tests feeding hostile URLs (javascript:alert(1), file:///etc/passwd) through your URL-handling code."],"tags":["url","protocol","config","browser"],"analyzedSha":"c3f553c740ebf3dff5e22dae24e9caaafafddd2d","analyzedAt":"2026-07-31T18:49:43.633Z","schemaVersion":2}