{"record":{"id":"7ed707596be6ef7e","repo":"xpipe-io/xpipe","slug":"unable-to-parse-or-decrypt-secret","errorCode":null,"errorMessage":"Unable to parse or decrypt secret","messagePattern":"Unable to parse or decrypt secret","errorType":"exception","errorClass":"BeaconClientException","httpStatus":400,"severity":"error","filePath":"app/src/main/java/io/xpipe/app/beacon/api/SecretDecryptExchange.java","lineNumber":25,"sourceCode":"import com.sun.net.httpserver.HttpExchange;\nimport lombok.Builder;\nimport lombok.NonNull;\nimport lombok.Value;\nimport lombok.extern.jackson.Jacksonized;\nimport tools.jackson.databind.JsonNode;\n\npublic class SecretDecryptExchange extends BeaconInterface<SecretDecryptExchange.Request> {\n\n    @Override\n    public String getPath() {\n        return \"/secret/decrypt\";\n    }\n\n    @Override\n    public Object handle(HttpExchange exchange, Request msg) throws BeaconClientException {\n        var secret = MultiPrincipalSecret.deserialize(msg.getEncrypted());\n        if (secret == null || secret.getInternalSecret() == null) {\n            throw new BeaconClientException(\"Unable to parse or decrypt secret\");\n        }\n\n        return Response.builder()\n                .decrypted(new String(secret.getInternalSecret().getSecret()))\n                .build();\n    }\n\n    @Jacksonized\n    @Builder\n    @Value\n    public static class Request {\n        @NonNull\n        JsonNode encrypted;\n    }\n\n    @Jacksonized\n    @Builder\n    @Value","sourceCodeStart":7,"sourceCodeEnd":43,"githubUrl":"https://github.com/xpipe-io/xpipe/blob/d85ca821baa46092a320ebb13546d7240adb74f8/app/src/main/java/io/xpipe/app/beacon/api/SecretDecryptExchange.java#L7-L43","documentation":"SecretDecryptExchange deserializes the client-supplied encrypted secret via MultiPrincipalSecret.deserialize(). If deserialization yields null or the payload lacks an internal secret, the daemon cannot parse or decrypt the value and rejects the request. Typically the ciphertext was truncated, corrupted, encrypted for another daemon instance, or is not in the expected container format.","triggerScenarios":"Posting an encrypted secret blob that is null, empty, base64-corrupted, produced by a different XPipe installation's key, or wrapped in an unexpected multi-principal structure so getInternalSecret() returns null.","commonSituations":"Copying the XPipe secrets vault/key between machines; hand-editing or truncating stored secret strings; passing a plaintext value where an encrypted container is expected; version mismatch between client serialization format and daemon parser.","solutions":["Re-obtain the encrypted secret from the original XPipe secret store rather than a copy","Verify the daemon instance you call is the one that encrypted the secret (same key/vault)","Confirm the value is sent as the full, unmodified base64 container (no truncation/whitespace)","Upgrade client and daemon together if the serialization format changed"],"exampleFix":"// before\nclient.decryptSecret(userSuppliedString);\n// after\nif (userSuppliedString == null || userSuppliedString.isBlank()) {\n    throw new IllegalArgumentException(\"encrypted secret required\");\n}\nclient.decryptSecret(userSuppliedString.trim());","handlingStrategy":"validation","validationCode":"if (encrypted == null || encrypted.isBlank()) {\n    throw new IllegalArgumentException(\"Encrypted secret payload is empty\");\n}","typeGuard":null,"tryCatchPattern":"try {\n    return client.decryptSecret(encrypted);\n} catch (BeaconClientException e) {\n    if (e.getMessage().contains(\"Unable to parse or decrypt\")) {\n        throw new IllegalStateException(\"Secret corrupt or encrypted by another daemon; re-encrypt it\", e);\n    }\n    throw e;\n}","preventionTips":["Only decrypt secrets produced by the same daemon instance/key","Send the full unmodified base64 container (trim whitespace, never truncate)","Keep client and daemon versions aligned on serialization format"],"tags":["beacon-api","secrets","decryption"],"backgroundTag":"checksum-mismatch","analyzedSha":"d85ca821baa46092a320ebb13546d7240adb74f8","analyzedAt":"2026-09-06T14:30:08.251Z","contentChangedAt":"2026-09-06T14:30:08.251Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}