{"record":{"id":"a920c1b02565b469","repo":"HMCL-dev/HMCL","slug":"texture-url-is-empty","errorCode":null,"errorMessage":"Texture url is empty","messagePattern":"Texture url is empty","errorType":"exception","errorClass":"IOException","httpStatus":null,"severity":"error","filePath":"HMCL/src/main/java/org/jackhuang/hmcl/game/TexturesLoader.java","lineNumber":95,"sourceCode":"\n    private static final ThreadPoolExecutor POOL = threadPool(\"TexturesDownload\", true, 2, 10, TimeUnit.SECONDS);\n    private static final Path TEXTURES_DIR = Metadata.HMCL_USER_HOME.resolve(\"skins\");\n\n    private static Path getTexturePath(Texture texture) {\n        String url = texture.url();\n        int slash = url.lastIndexOf('/');\n        int dot = url.lastIndexOf('.');\n        if (dot < slash) {\n            dot = url.length();\n        }\n        String hash = url.substring(slash + 1, dot);\n        String prefix = hash.length() > 2 ? hash.substring(0, 2) : \"xx\";\n        return TEXTURES_DIR.resolve(prefix).resolve(hash);\n    }\n\n    public static LoadedTexture loadTexture(Texture texture) throws Throwable {\n        if (StringUtils.isBlank(texture.url())) {\n            throw new IOException(\"Texture url is empty\");\n        }\n\n        Path file = getTexturePath(texture);\n        if (!Files.isRegularFile(file)) {\n            // download it\n            try {\n                new FileDownloadTask(texture.url(), file).run();\n                LOG.info(\"Texture downloaded: \" + texture.url());\n            } catch (Exception e) {\n                if (Files.isRegularFile(file)) {\n                    // concurrency conflict?\n                    LOG.warning(\"Failed to download texture \" + texture.url() + \", but the file is available\", e);\n                } else {\n                    throw new IOException(\"Failed to download texture \" + texture.url());\n                }\n            }\n        }\n","sourceCodeStart":77,"sourceCodeEnd":113,"githubUrl":"https://github.com/HMCL-dev/HMCL/blob/24702dc5a0214034f4c27166d5fd30cad08cec19/HMCL/src/main/java/org/jackhuang/hmcl/game/TexturesLoader.java#L77-L113","documentation":"loadTexture throws this IOException when a Minecraft skin/cape texture has a blank (null or whitespace-only) URL. The texture metadata exists but points to nothing, so there is no URL to download or hash from. It surfaces when HMCL tries to render the player skin.","triggerScenarios":"Calling TexturesLoader.loadTexture(texture) with a Texture whose url() is blank; commonly reached through skinBinding when authentication returned a profile whose textures entry has no url property.","commonSituations":"Offline/cracked accounts with no uploaded skin; legacy profiles missing the texture URL; Mojang/Yggdrasil servers returning texture metadata without a URL; custom auth servers with incomplete texture responses.","solutions":["Check StringUtils.isBlank(texture.url()) before calling loadTexture and fall back to a default/steve skin","Re-login to refresh the profile so the texture metadata includes a URL","If using a custom auth server, fix it to return the texture url field","Wrap the call in try-catch and render a fallback texture instead of failing"],"exampleFix":"// before\nLoadedTexture tex = TexturesLoader.loadTexture(texture);\n// after\nif (StringUtils.isBlank(texture.url())) {\n    texture = DEFAULT_STEVE_TEXTURE; // or skip skin rendering\n}\nLoadedTexture tex = TexturesLoader.loadTexture(texture);","handlingStrategy":"fallback","validationCode":"if (texture == null || StringUtils.isBlank(texture.url())) {\n    texture = DEFAULT_SKIN_TEXTURE;\n}","typeGuard":"boolean hasTextureUrl(Texture t) {\n    return t != null && !StringUtils.isBlank(t.url());\n}","tryCatchPattern":"try {\n    LoadedTexture tex = TexturesLoader.loadTexture(texture);\n} catch (IOException e) {\n    LOG.warning(\"No texture URL, falling back to default skin\", e);\n    return DEFAULT_LOADED_TEXTURE;\n}","preventionTips":["Validate texture metadata (url non-blank) after login before rendering","Refresh sessions when profile data looks stale","Render a default skin for offline accounts proactively"],"tags":["java","ioexception","empty-value","skin"],"backgroundTag":"empty-required-field","analyzedSha":"24702dc5a0214034f4c27166d5fd30cad08cec19","analyzedAt":"2026-09-10T12:36:46.680Z","contentChangedAt":"2026-09-10T12:36:46.680Z","schemaVersion":2},"datasetVersion":"2026-09-15T23:17:13.987Z"}