{"record":{"id":"62ee2d9a0ff84c0d","repo":"xpipe-io/xpipe","slug":"principals-must-not-be-empty","errorCode":null,"errorMessage":"Principals must not be empty","messagePattern":"Principals must not be empty","errorType":"exception","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"app/src/main/java/io/xpipe/app/storage/DataStoreAccessScope.java","lineNumber":101,"sourceCode":"    public static DataStoreAccessScope vault() {\n        return new DataStoreAccessScope(\n                Set.of(DataStorageAccessHandler.getInstance().getFallbackPrincipal()));\n    }\n\n    public static DataStoreAccessScope encryption() {\n        return new DataStoreAccessScope(\n                Set.of(DataStorageAccessHandler.getInstance().getEncryptAllPrincipal()));\n    }\n\n    public static DataStoreAccessScope of(Set<EncryptionPrincipal> encryptionPrincipals) {\n        return new DataStoreAccessScope(encryptionPrincipals);\n    }\n\n    private final Set<EncryptionPrincipal> principals;\n\n    private DataStoreAccessScope(Set<EncryptionPrincipal> principals) {\n        if (principals.isEmpty()) {\n            throw new IllegalArgumentException(\"Principals must not be empty\");\n        }\n\n        var vault = DataStorageAccessHandler.getInstance().getFallbackPrincipal();\n        var encrypt = DataStorageAccessHandler.getInstance().getEncryptAllPrincipal();\n        if (principals.contains(vault)) {\n            this.principals = treeSet(Set.of(vault));\n        } else if (principals.contains(encrypt)) {\n            this.principals = treeSet(Set.of(encrypt));\n        } else {\n            this.principals = treeSet(principals);\n        }\n    }\n\n    public boolean isAccessSubRestricted() {\n        var all = this.equals(encryption()) || this.equals(vault());\n        return !all;\n    }\n","sourceCodeStart":83,"sourceCodeEnd":119,"githubUrl":"https://github.com/xpipe-io/xpipe/blob/d85ca821baa46092a320ebb13546d7240adb74f8/app/src/main/java/io/xpipe/app/storage/DataStoreAccessScope.java#L83-L119","documentation":"DataStoreAccessScope is an immutable scope of encryption principals; its private constructor requires at least one principal because an access scope with no principals is meaningless — nothing could decrypt data in it. It throws IllegalArgumentException immediately when handed an empty set.","triggerScenarios":"Calling DataStoreAccessScope.of()/factory or the private constructor path with an empty Set<EncryptionPrincipal>, e.g. after filtering principals and getting an empty result, or building a scope from a collection that was never populated.","commonSituations":"Computing the intersection of allowed principals across users and getting an empty set; loading principal lists from config/vault where none were found; filtering out principals the current user cannot access.","solutions":["Ensure the principal set has at least one entry before constructing the scope; bail out earlier with a clear message if the list is empty.","Fall back to the vault principal (DataStorageAccessHandler.getInstance().getFallbackPrincipal()) when no user principals are available.","Fix the upstream filtering logic so allowed principals are actually collected."],"exampleFix":"// before\nvar scope = DataStoreAccessScope.of(collectedPrincipals); // throws when empty\n// after\nif (collectedPrincipals.isEmpty()) {\n    collectedPrincipals = Set.of(DataStorageAccessHandler.getInstance().getFallbackPrincipal());\n}\nvar scope = DataStoreAccessScope.of(collectedPrincipals);","handlingStrategy":"validation","validationCode":"if (principals == null || principals.isEmpty()) {\n    throw new IllegalArgumentException(\"At least one encryption principal is required\");\n}","typeGuard":null,"tryCatchPattern":"try {\n    var scope = DataStoreAccessScope.of(principals);\n} catch (IllegalArgumentException e) {\n    // fall back to the vault principal\n}","preventionTips":["Never construct scopes from unfiltered, possibly empty principal sets.","Fall back to the fallback principal when user filtering yields nothing.","Log which filtering step removed all principals."],"tags":["java","encryption","illegal-argument","empty-collection"],"backgroundTag":"empty-required-field","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"}