valyala/fasthttp · error

invalid scheme %q

Error message

invalid scheme %q

What it means

fasthttp's URI.Parse validates the scheme extracted when the URI contains a host part. If splitHostURI yields a non-empty scheme that fails isValidScheme (only alphanumerics, '+', '-', '.' allowed), parse returns "invalid scheme %q". Parse is fasthttp's low-level URI parsing entry point used when rebinding URIs from raw bytes.

Source

Thrown at uri.go:293

// host may be nil. In this case uri must contain fully qualified uri,
// i.e. with scheme and host. http is assumed if scheme is omitted.
//
// uri may contain e.g. RequestURI without scheme and host if host is non-empty.
func (u *URI) Parse(host, uri []byte) error {
	return u.parse(host, uri, false)
}

func (u *URI) parse(host, uri []byte, isTLS bool) error {
	u.Reset()

	if stringContainsCTLByte(uri) {
		return ErrorInvalidURI
	}

	if len(host) == 0 || bytes.Contains(uri, strColonSlashSlash) {
		scheme, newHost, newURI := splitHostURI(host, uri)
		if len(scheme) > 0 && !isValidScheme(scheme) {
			return fmt.Errorf("invalid scheme %q", scheme)
		}
		u.SetSchemeBytes(scheme)
		host = newHost
		uri = newURI
	}

	if isTLS {
		u.SetSchemeBytes(strHTTPS)
	}

	if n := bytes.LastIndexByte(host, '@'); n >= 0 {
		auth := host[:n]
		if !validUserinfo(auth) {
			return ErrorInvalidURI
		}
		host = host[n+1:]

		if before, after, ok := bytes.Cut(auth, []byte{':'}); ok {

View on GitHub (pinned to c96f600972)

Solutions

  1. Sanitize/validate the scheme before calling Parse (regex ^[a-zA-Z][a-zA-Z0-9+.-]*$)
  2. Normalize to lowercase http/https at the producer side
  3. If the input is a request line, use RequestHeader/Request parsing instead of raw URI.Parse
  4. Catch the error and reject the request with 400 Bad Request

Example fix

// before
var u uri.URI
err := u.Parse(nil, nil, []byte("ht tp://example.com/")) // invalid scheme
// after
raw := []byte("ht tp://example.com/")
if !isValidSchemeBytes(raw) { // reject or fix before parse
    return errors.New("bad scheme")
}
var u uri.URI
err := u.Parse(nil, nil, raw)
Defensive patterns

Strategy: validation

Validate before calling

var schemeRe = regexp.MustCompile(`^[a-zA-Z][a-zA-Z0-9+.-]*$`)
func schemeValid(raw []byte) bool {
    i := bytes.Index(raw, []byte("://"))
    return i < 0 || schemeRe.Match(raw[:i])
}

Try / catch

var u uri.URI
if err := u.Parse(nil, nil, raw); err != nil {
    if strings.HasPrefix(err.Error(), "invalid scheme") {
        return fmt.Errorf("rejecting request, %w", err) // map to 400
    }
    return err
}

Prevention

When it happens

Trigger: Calling URI.Parse(nil, dst, uri) with a URI whose scheme contains illegal characters, e.g. "ht tp://host/", "http$://host/", or a malformed proxy-form request line that mis-splits into a bogus scheme.

Common situations: Parsing attacker-supplied or corrupted request targets; reverse-proxy code feeding raw request lines into Parse; hand-built URIs with typos like "hxxp://".

Related errors


AI-assisted analysis of valyala/fasthttp@c96f600972 (2026-08-31). Data as JSON: /api/errors/794d6953d6ba7f86. Report an issue: GitHub.