apple/pkl · error · VmException

cannotResolveTripleDotImports

cannotResolveTripleDotImports

Error message

Cannot resolve a triple-dot import from module URI `{0}`.

What it means

Triple-dot imports (import "...") resolve relative to the enclosing project/package root. This eval error is thrown when the module performing the triple-dot import is not a local module with hierarchical URIs, so the '...' root cannot be computed.

Source

Thrown at pkl-core/src/main/java/org/pkl/core/util/IoUtils.java:376

  public static URI resolve(ReaderBase reader, URI baseUri, String importUri) {
    return resolve(reader, baseUri, createUri(importUri));
  }

  public static URI resolve(ReaderBase reader, URI baseUri, URI importUri) {
    if (reader.hasFragmentPaths() && !importUri.isAbsolute() && importUri.getPath() != null) {
      var fragment = baseUri.getFragment();
      var newFragment = resolve(createUri(fragment), importUri);
      return stripFragment(baseUri).resolve("#" + newFragment);
    }
    return resolve(baseUri, importUri);
  }

  private static URI resolveTripleDotImport(
      SecurityManager securityManager, ModuleKey moduleKey, String tripleDotPath)
      throws IOException, SecurityManagerException, ExternalReaderProcessException {
    var moduleKeyUri = moduleKey.getUri();
    if (!moduleKey.isLocal() || !moduleKey.hasHierarchicalUris()) {
      throw new VmExceptionBuilder()
          .evalError("cannotResolveTripleDotImports", moduleKeyUri)
          .build();
    }
    var currentPath =
        moduleKey.hasFragmentPaths() ? moduleKeyUri.getFragment() : moduleKeyUri.getPath();
    var effectiveImportPath =
        tripleDotPath.isEmpty()
            ? currentPath.substring(currentPath.lastIndexOf('/') + 1)
            : tripleDotPath;

    var index = currentPath.lastIndexOf('/');
    index = currentPath.lastIndexOf('/', index - 1);
    var basePath = currentPath;
    while (index > 0) {
      basePath = basePath.substring(0, index + 1);
      var candidatePath = basePath + effectiveImportPath;
      // make sure triple-dot cannot resolve to the same path.
      var candidateUri = resolve(moduleKey, moduleKeyUri, candidatePath);

View on GitHub (pinned to f3efcbfc9b)

Solutions

  1. Move the import so it is only used in local files on disk
  2. Use a fully-qualified package or absolute URI import instead of triple-dot in remote modules
  3. If the module should be local, load it via a file: URI

Example fix

// before (inside an http-served module)
import ".../my_module.pkl"
// after
import "@my_package/my_module.pkl"
Defensive patterns

Strategy: validation

Validate before calling

if (importPath.startsWith("...") && !moduleUri.getScheme().equals("file")) {
  throw new IllegalArgumentException("triple-dot import only valid in local modules");
}

Type guard

function supportsTripleDot(key) { return key.isLocal() && key.hasHierarchicalUris(); }

Try / catch

try { resolveTripleDotImport(...) } catch (VmException e) { logger.error(e.getMessage()); }

Prevention

When it happens

Trigger: resolveTripleDotImport is invoked with a moduleKey that is remote (http:, package:, project:) or otherwise lacks hierarchical URIs, e.g. `import "..."` inside a module fetched from an HTTP URL or loaded from a package.

Common situations: Writing `import ".../foo.pkl"` in a module that is itself loaded over http(s) or from a Pkl package, where relative filesystem resolution is impossible.

Understand the failure class

Background: UnsupportedOperationException and "is not supported" errors: when a library deliberately refuses a call — this error's family across 30 libraries.

Related errors


AI-assisted analysis of apple/pkl@f3efcbfc9b (2026-09-08). Data as JSON: /api/errors/1b1bd9c9c2caeb03. Report an issue: GitHub.