Tencent/WeKnora · error

unsupported URL scheme: %s

Error message

unsupported URL scheme: %s

What it means

DownloadBytes only accepts absolute http:// or https:// URLs; anything else (ftp:, file:, ws:, or scheme-less strings) is rejected before any network activity. This guard ensures the function only performs HTTP GETs.

Source

Thrown at internal/utils/httputil.go:20

import (
	"fmt"
	"io"
	"net/http"
	"strings"
	"time"
)

var defaultHTTPClient = NewSSRFSafeHTTPClient(SSRFSafeHTTPClientConfig{
	Timeout:      60 * time.Second,
	MaxRedirects: 10,
})

// DownloadBytes fetches the content at the given HTTP(S) URL and returns the
// raw bytes. It reuses a package-level http.Client with a 60-second timeout.
func DownloadBytes(url string) ([]byte, error) {
	if !strings.HasPrefix(url, "http://") && !strings.HasPrefix(url, "https://") {
		return nil, fmt.Errorf("unsupported URL scheme: %s", url)
	}
	if err := ValidateURLForSSRF(url); err != nil {
		return nil, fmt.Errorf("URL rejected by SSRF policy: %w", err)
	}
	resp, err := defaultHTTPClient.Get(url)
	if err != nil {
		return nil, fmt.Errorf("HTTP GET: %w", err)
	}
	defer resp.Body.Close()
	if resp.StatusCode != http.StatusOK {
		return nil, fmt.Errorf("HTTP %d for %s", resp.StatusCode, url)
	}
	data, err := io.ReadAll(resp.Body)
	if err != nil {
		return nil, fmt.Errorf("read body: %w", err)
	}
	return data, nil
}

View on GitHub (pinned to 988cbb0330)

Solutions

  1. Prefix the URL with https:// (or http://) before calling DownloadBytes
  2. For local files, read with os.ReadFile instead of DownloadBytes
  3. Normalize/complete the URL when it comes from config or user input
  4. If other schemes are needed, resolve them separately and hand DownloadBytes only the https endpoint

Example fix

// before
DownloadBytes("example.com/data.json")
// after
DownloadBytes("https://example.com/data.json")
Defensive patterns

Strategy: validation

Validate before calling

u, err := url.Parse(raw)
if err != nil || (u.Scheme != "http" && u.Scheme != "https") {
    return fmt.Errorf("must be an http(s) URL")
}

Type guard

func isHTTPURL(raw string) bool {
    u, err := url.Parse(raw)
    return err == nil && (u.Scheme == "http" || u.Scheme == "https") && u.Host != ""
}

Try / catch

data, err := DownloadBytes(url)
if err != nil {
    if strings.Contains(err.Error(), "unsupported URL scheme") {
        // normalize URL or fall back to a file/scheme-specific reader
    }
}

Prevention

When it happens

Trigger: Calling DownloadBytes with a URL lacking an http(s) prefix: file:// paths, data: URIs, relative paths like "/api/x", hostnames without a scheme ("example.com/file"), or other schemes (ftp, s3).

Common situations: Passing a local file path expecting the helper to read disk, config storing scheme-less URLs, URLs taken from user input without normalization, or S3/blob-store URIs handed to a generic downloader.

Related errors


AI-assisted analysis of Tencent/WeKnora@988cbb0330 (2026-09-02). Data as JSON: /api/errors/91d91768c8ee3366. Report an issue: GitHub.