cryptomator/cryptomator · error · IOException

Failed to parse JWE

Error message

Failed to parse JWE

What it means

ReceiveKeyController.receivedLegacyAccessTokenSuccess parses a raw legacy access token as a JWEObject; a ParseException (token not valid compact JWE serialization) is rethrown as IOException("Failed to parse JWE"). The token delivered by the legacy Hub flow could not be structurally parsed.

Source

Thrown at src/main/java/org/cryptomator/ui/keyloading/hub/ReceiveKeyController.java:297

				case 402 -> licenseExceeded();
				case 403 -> accessNotGranted();
				case 410 -> accessGoneVaultArchived();
				case 404 -> needsLegacyDeviceRegistration();
				default -> throw new IOException("Unexpected response " + response.statusCode());
			}
		} catch (IOException e) {
			throw new UncheckedIOException(e);
		}
	}

	@Deprecated
	private void receivedLegacyAccessTokenSuccess(String rawToken) throws IOException {
		try {
			var token = JWEObject.parse(rawToken);
			result.complete(ReceivedKey.legacyDeviceKey(token));
			window.close();
		} catch (ParseException e) {
			throw new IOException("Failed to parse JWE", e);
		}
	}

	private void licenseExceeded() {
		window.setScene(invalidLicenseScene.get());
	}

	@Deprecated
	private void needsLegacyDeviceRegistration() {
		window.setScene(legacyRegisterDeviceScene.get());
	}

	private void accessNotGranted() {
		window.setScene(unauthorizedScene.get());
	}

	private void accessGoneVaultArchived() {
		window.close();

View on GitHub (pinned to af99135172)

Solutions

  1. Log/inspect the raw token's first characters — it should start with five dot-separated Base64URL segments
  2. Verify the Hub server actually supports the legacy token flow being used; upgrade client or server to matching versions
  3. Retry the key-receive flow to get a fresh token
  4. Check for proxies/URL handlers mangling the token before it reaches the controller

Example fix

// before
catch (ParseException e) { throw new IOException("Failed to parse JWE", e); }
// after: fail with diagnostics
catch (ParseException e) {
    LOG.error("token not JWE: {}...", rawToken.substring(0, Math.min(20, rawToken.length())));
    throw new IOException("Failed to parse JWE", e);
}
Defensive patterns

Strategy: validation

Validate before calling

static boolean looksLikeJwe(String token) {
    return token != null && token.chars().filter(c -> c == '.').count() == 4;
}

Type guard

static boolean isParseableJwe(String raw) { try { JWEObject.parse(raw); return true; } catch (ParseException e) { return false; } }

Try / catch

try { receivedLegacyAccessTokenSuccess(rawToken); } catch (IOException e) { showInvalidTokenScene(); LOG.error("token not JWE", e.getCause()); }

Prevention

When it happens

Trigger: The legacy access token string handed to receivedLegacyAccessTokenSuccess (via receivedLegacyAccessTokenResponse) is empty, HTML (e.g. an error page), truncated, or otherwise not in JWE compact serialization, causing JWEObject.parse to throw ParseException.

Common situations: Hub server returning an error page instead of the token, legacy flow interrupted producing partial token, copy/paste or clipboard corruption of the token, Hub version emitting a plain JWT where a JWE is expected.

Understand the failure class

Related errors


AI-assisted analysis of cryptomator/cryptomator@af99135172 (2026-09-05). Data as JSON: /api/errors/66998113d8a2ffc2. Report an issue: GitHub.