apple/pkl · error · URISyntaxException
invalidRelativePathInPackageUri
invalidRelativePathInPackageUri
Error message
invalidRelativePathInPackageUri
What it means
Thrown by the PackageUri constructor when the package URI path contains a '..' segment (literally or percent-encoded). Parent-directory segments are rejected to keep package URIs canonical and prevent path traversal within package identifiers.
Source
Thrown at pkl-core/src/main/java/org/pkl/core/packages/PackageUri.java:67
var scheme = uri.getScheme();
if (scheme == null || !(scheme.equals("package") || scheme.equals("projectpackage"))) {
throw new URISyntaxException(
uri.toString(), ErrorMessages.create("invalidSchemeInPackageUri", scheme));
}
var authority = uri.getAuthority();
if (authority == null || authority.isEmpty()) {
throw new URISyntaxException(
uri.toString(), ErrorMessages.create("missingAuthorityInPackageUri", uri));
}
var path = uri.getPath();
if (path == null || path.isEmpty()) {
throw new URISyntaxException(
uri.toString(), ErrorMessages.create("missingPathInPackageUri", uri));
}
// reject `..` segments, percent-encoded or not
for (var segment : path.split("/", -1)) {
if (segment.equals("..")) {
throw new URISyntaxException(
uri.toString(), ErrorMessages.create("invalidRelativePathInPackageUri"));
}
}
var versionIdx = path.lastIndexOf('@');
if (versionIdx == -1) {
throw new URISyntaxException(
uri.toString(), ErrorMessages.create("missingVersionInPackageUri", path));
}
this.uri = IoUtils.stripFragment(uri);
this.pathWithoutVersion = path.substring(0, versionIdx);
var checksumIdx = path.indexOf("::");
var versionPart = path.substring(versionIdx + 1);
if (checksumIdx > versionIdx) {
var checksumPart = path.substring(checksumIdx + 2);
versionPart = path.substring(versionIdx + 1, checksumIdx);
this.checksums = parseChecksumPart(checksumPart);
}
try {View on GitHub (pinned to f3efcbfc9b)
Solutions
- Remove all '..' segments and use a canonical absolute package path
- Normalize the path (or reject the input) before constructing the PackageUri
- Use the package name exactly as published instead of a computed relative path
Example fix
// before
var uri = URI.create("package://example.com/a/../my-pkg@1.2.3");
var pkg = new PackageUri(uri);
// after
var uri = URI.create("package://example.com/my-pkg@1.2.3");
var pkg = new PackageUri(uri); Defensive patterns
Strategy: validation
Validate before calling
boolean hasNoDotDotSegments(String path) {
for (var segment : path.split("/", -1)) {
if (segment.equals("..")) return false;
}
return true;
} Type guard
static boolean isCanonicalPackagePath(URI uri) {
var path = uri.getPath();
if (path == null) return false;
for (var segment : path.split("/", -1)) {
if (segment.equals("..")) return false;
}
return true;
} Try / catch
try {
var pkg = new PackageUri(uri);
} catch (URISyntaxException e) {
throw new IllegalArgumentException("Package URI must not contain '..' segments: " + uri, e);
} Prevention
- Normalize relative paths before embedding them in a URI
- Never build package URIs from unnormalized user paths
- Reject '..' (including percent-encoded) early in input validation
When it happens
Trigger: new PackageUri(uri) where any path segment split on '/' equals '..', e.g. 'package://example.com/../other@1.0.0' or with %2E%2E encoded segments.
Common situations: Programmatically resolving relative paths and forgetting normalization before building the URI; template/concatenation bugs injecting '..'; attempting to smuggle traversal segments into a dependency URI (caught by design).
Understand the failure class
Background: Path traversal blocked: "path escapes the workspace" and "outside site root" errors when a path will not stay inside its allowed directory — this error's family across 26 libraries.
Related errors
- invalidSchemeInPackageUri
- missingAuthorityInPackageUri
- missingPathInPackageUri
- missingVersionInPackageUri
- resourcePastRootDir|modulePastRootDir
AI-assisted analysis of apple/pkl@f3efcbfc9b (2026-09-08).
Data as JSON: /api/errors/b56d535cb346d37d.
Report an issue: GitHub.