HMCL-dev/HMCL · error · InvalidSkinException
Failed to read skin image
Error message
Failed to read skin image
What it means
Thrown by AccountListItem.uploadSkin when the locally selected skin file cannot be opened/read via Files.newInputStream — an IOException while reading the user-chosen skin file before upload. Wrapped in InvalidSkinException so the upload task fails with a user-facing message.
Solutions
- Confirm the skin file still exists and is readable, then re-select it in the account skin dialog
- Close any application holding a lock on the file and retry
- Copy the skin to a local writable path and upload from there
- Catch InvalidSkinException in the upload task and show the message to the user
Example fix
// before
accountListItem.uploadSkin(selectedFile);
// after
try {
accountListItem.uploadSkin(selectedFile);
} catch (InvalidSkinException e) {
LOG.warning("Skin upload failed: " + e.getMessage(), e);
Dialogs.error("Could not read the skin file: " + selectedFile);
} Defensive patterns
Strategy: validation
Validate before calling
if (!Files.isReadable(selectedFile)) throw new IllegalArgumentException("Skin file not readable: " + selectedFile);
if (Files.size(selectedFile) == 0) throw new IllegalArgumentException("Skin file is empty"); Try / catch
try {
accountListItem.uploadSkin(file);
} catch (InvalidSkinException e) {
Dialogs.error("Skin upload failed: " + e.getMessage());
} Prevention
- Re-check file existence/readability right before upload
- Avoid holding the file open in other apps during upload
- Copy user-selected files to a temp location before async processing
- Show file pickers rooted at stable local directories
When it happens
Trigger: The selected skin file was moved/deleted between selection and upload, the file is locked by another process, or permission/network storage errors occur while opening the FileInputStream.
Common situations: User deletes or renames the skin PNG after picking it in the file chooser; file on a removable drive/UNC path that became unavailable; OS-level file lock from another application.
Understand the failure class
Background: "failed to read file", EACCES, ENOENT and "could not read <path>" errors: when a program can't read a file from disk — this error's family across 49 libraries.
Related errors
- Asset index file malformed
- Bad exit code
- Cannot export a background directory as a theme-pack asset
- Cannot find suitable encoding for the zip.
- Cannot parse the version of
AI-assisted analysis of HMCL-dev/HMCL@24702dc5a0 (2026-09-10).
Data as JSON: /api/errors/07743fd91f11119f.
Report an issue: GitHub.
Appendix: source
Thrown at HMCL/src/main/java/org/jackhuang/hmcl/ui/account/AccountListItem.java:164
if (!account.canUploadSkin()) {
return null;
}
FileChooser chooser = new FileChooser();
chooser.setTitle(i18n("account.skin.upload"));
chooser.getExtensionFilters().add(new FileChooser.ExtensionFilter(i18n("account.skin.file"), "*.png"));
Path selectedFile = Controllers.showOpenDialog(chooser);
if (selectedFile == null) {
return null;
}
return refreshAsync()
.thenRunAsync(() -> {
Image skinImg;
try (var input = Files.newInputStream(selectedFile)) {
skinImg = new Image(input);
} catch (IOException e) {
throw new InvalidSkinException("Failed to read skin image", e);
}
if (skinImg.isError()) {
throw new InvalidSkinException("Failed to read skin image", skinImg.getException());
}
if (skinImg.getWidth() != 64 || (skinImg.getHeight() != 32 && skinImg.getHeight() != 64)) {
throw new InvalidSkinException("Invalid skin size");
}
NormalizedSkin skin = new NormalizedSkin(skinImg);
String model = skin.isSlim() ? "slim" : "";
LOG.info("Uploading skin [" + selectedFile + "], model [" + model + "]");
account.uploadSkin(skin.isSlim(), selectedFile);
})
.thenComposeAsync(refreshAsync())
.whenComplete(Schedulers.javafx(), e -> {
if (e != null) {
Controllers.dialog(Accounts.localizeErrorMessage(e), i18n("account.skin.upload.failed"), MessageType.ERROR);
}
});View on GitHub (pinned to 24702dc5a0)