{"record":{"id":"3535631f7f0f464f","repo":"apple/pkl","slug":"package-resolver-has-already-been-closed","errorCode":null,"errorMessage":"Package resolver has already been closed.","messagePattern":"Package resolver has already been closed\\.","errorType":"exception","errorClass":"IllegalStateException","httpStatus":null,"severity":"error","filePath":"pkl-core/src/main/java/org/pkl/core/packages/PackageResolvers.java","lineNumber":245,"sourceCode":"\n    protected abstract List<PathElement> doListElements(\n        PackageAssetUri uri, @Nullable Checksums checksums)\n        throws IOException, SecurityManagerException;\n\n    protected abstract boolean doHasElement(PackageAssetUri uri, @Nullable Checksums checksums)\n        throws IOException, SecurityManagerException;\n\n    protected PackageLoadError invalidPackageZipUrl(\n        PackageUri packageUri, DependencyMetadata dependencyMetadata) {\n      return new PackageLoadError(\n          \"invalidPackageZipUrl\",\n          packageUri.getDisplayName(),\n          dependencyMetadata.getPackageZipUrl());\n    }\n\n    private void checkNotClosed() {\n      if (isClosed.get()) {\n        throw new IllegalStateException(\"Package resolver has already been closed.\");\n      }\n    }\n  }\n\n  /**\n   * A package resolver that holds entire package contents in memory.\n   *\n   * <p>This gets used when the cache dir is not set.\n   */\n  static final class InMemoryPackageResolver extends AbstractPackageResolver {\n    @GuardedBy(\"lock\")\n    private final EconomicMap<PackageUri, EconomicMap<String, ByteBuffer>> cachedEntries =\n        EconomicMaps.create();\n\n    @GuardedBy(\"lock\")\n    private final EconomicMap<PackageUri, TreePathElement> cachedTreePathElementRoots =\n        EconomicMaps.create();\n","sourceCodeStart":227,"sourceCodeEnd":263,"githubUrl":"https://github.com/apple/pkl/blob/f3efcbfc9b60d30053b0536d664948d7aa1b8673/pkl-core/src/main/java/org/pkl/core/packages/PackageResolvers.java#L227-L263","documentation":"IllegalStateException thrown by checkNotClosed when a package resolver's API (getDependencyMetadata, listElements, hasElement) is used after the resolver was closed. Resolvers are one-shot resources; once closed, all further lookups are invalid.","triggerScenarios":"Calling getDependencyMetadata, listElements, or hasElement on a PackageResolver after close() was called on it (or on its parent ProjectPackageResolver / resolver manager).","commonSituations":"Holding a resolver reference beyond the scope that closed it; closing a resolver in a finally block and reusing it afterwards; sharing a resolver across concurrent tasks where one task closes it early.","solutions":["Do not use the resolver after calling close(); obtain a fresh resolver instance for subsequent operations","Restructure code so all resolver calls happen inside the try block of a try-with-resources statement","Check for premature close() calls (e.g. in finally blocks or shutdown hooks) that run before remaining lookups","Ensure concurrent code doesn't share one resolver across threads with differing lifetimes"],"exampleFix":"// before\nvar resolver = PackageResolvers.open(...);\nresolver.close();\nresolver.getDependencyMetadata(uri); // throws\n// after\ntry (var resolver = PackageResolvers.open(...)) {\n  resolver.getDependencyMetadata(uri);\n}","handlingStrategy":"try-catch","validationCode":"// guard before use\nif (resolver.isClosed()) throw new IllegalStateException(\"resolver closed\");","typeGuard":"boolean isUsable(PackageResolver r) { return r != null && !r.isClosed(); }","tryCatchPattern":"try {\n  resolver.getDependencyMetadata(uri);\n} catch (IllegalStateException e) {\n  if (e.getMessage().contains(\"already been closed\")) {\n    resolver = reopenResolver(); // reacquire and retry once\n  }\n}","preventionTips":["Use try-with-resources so close() only runs at scope exit","Never store resolver references in long-lived fields","Don't close a shared resolver while other tasks may still use it","Keep resolver creation and use in the same method/scope"],"tags":["resource-lifecycle","closed-resource","package-loading"],"backgroundTag":"invalid-state-transition","analyzedSha":"f3efcbfc9b60d30053b0536d664948d7aa1b8673","analyzedAt":"2026-09-08T13:10:45.570Z","contentChangedAt":"2026-09-08T13:10:45.570Z","schemaVersion":2},"datasetVersion":"2026-09-17T15:17:12.973Z"}