HMCL-dev/HMCL · error · IOException

Theme background URL must be HTTP or HTTPS

Error message

Theme background URL must be HTTP or HTTPS: ${url}

What it means

Thrown by ThemePackManager when resolving a network background whose URL scheme is not HTTP or HTTPS (e.g. ftp:, file:, data:). The downloader only supports HttpURLConnection-based fetching, so non-HTTP(S) URIs are rejected before any download is attempted.

Solutions

  1. Replace the URL with an http:// or https:// link to the image.
  2. If the image is local, use a background imagePath/file background instead of networkImageUrl.
  3. If you need data-URI backgrounds, download the image and reference it as a local asset first.

Example fix

// before
"background": { "url": "file:///home/user/wall.png" }
// after
"background": { "url": "https://example.com/wall.png" }
Defensive patterns

Strategy: validation

Validate before calling

URI uri = URI.create(url);
if (!"http".equalsIgnoreCase(uri.getScheme()) && !"https".equalsIgnoreCase(uri.getScheme())) {
    throw new IllegalArgumentException("background url must be http(s): " + url);
}

Type guard

static boolean isHttpUrl(String url) {
    try {
        String s = URI.create(url).getScheme();
        return "http".equalsIgnoreCase(s) || "https".equalsIgnoreCase(s);
    } catch (IllegalArgumentException e) { return false; }
}

Prevention

When it happens

Trigger: Setting a theme background with networkImageUrl set to a non-HTTP(S) URI; NetworkUtils.toURI(url) parses it but NetworkUtils.isHttpUri(uri) returns false.

Common situations: Pasting a file:// or data:image/... URL into a theme's background.url field; using an ftp:// mirror link; authoring a manifest by hand with a localhost or custom-scheme URL.

Understand the failure class

Background: "Invalid URL" / "URL cannot be empty": fix the malformed or missing URL behind request-construction failures — this error's family across 50 libraries.

Related errors


AI-assisted analysis of HMCL-dev/HMCL@24702dc5a0 (2026-09-10). Data as JSON: /api/errors/6a8b6cb0c8f3181b. Report an issue: GitHub.

Appendix: source

Thrown at HMCL/src/main/java/org/jackhuang/hmcl/theme/ThemePackManager.java:1502

        }
        if (!Files.isRegularFile(source)) {
            throw new IOException("Theme background image does not exist: " + source);
        }

        String entryName = "assets/wallpapers/" + sanitizePathSegment(source.getFileName().toString());
        assets.add(new ThemePackAsset(source, entryName));
        return new ThemeBackground.Image(entryName);
    }

    /// Downloads the current network background and exports it as a theme-pack image asset.
    private static ThemeBackground.Image createCurrentNetworkBackgroundSource(
            List<ThemePackAsset> assets,
            List<Path> temporaryFiles,
            ResolvedBackground background) throws IOException {
        String url = requireNonBlank(background.networkImageUrl(), "background.url");
        URI uri = NetworkUtils.toURI(url);
        if (!NetworkUtils.isHttpUri(uri)) {
            throw new IOException("Theme background URL must be HTTP or HTTPS: " + url);
        }

        String entryName = "assets/wallpapers/" + networkBackgroundAssetName(uri);
        if (background.networkImageCachePolicy() == NetworkBackgroundImageCachePolicy.ENABLED) {
            try {
                @Nullable Path cachedFile = new CacheFileTask(uri).run();
                if (cachedFile != null && Files.isRegularFile(cachedFile)) {
                    assets.add(new ThemePackAsset(cachedFile, entryName));
                    return new ThemeBackground.Image(entryName);
                }
            } catch (Exception e) {
                LOG.warning("Failed to cache theme background, falling back to direct download: " + uri, e);
            }
        }

        Path temporaryFile = Files.createTempFile("hmcl-theme-background-", ".tmp");
        boolean success = false;
        try {

View on GitHub (pinned to 24702dc5a0)