theonedev/onedev · error · BlobEditException

Invalid old path: <oldPath>

Error message

Invalid old path: <oldPath>

What it means

The BlobEdits constructor normalizes every path in the oldPaths set via GitUtils.normalizePath, which returns null for paths that are invalid in git terms (empty, absolute, containing '..' or otherwise unnormalizable). If any old path fails normalization, a BlobEditException is thrown at construction time so a malformed edit set is never built.

Source

Thrown at server-core/src/main/java/io/onedev/server/git/BlobEdits.java:43

	
	private static final long serialVersionUID = 1L;

	private final Set<String> oldPaths;
	
	private final Map<String, BlobContent> newBlobs;
	
	public BlobEdits() {
		this(new HashSet<>(), new HashMap<>());
	}
	
	public BlobEdits(Set<String> oldPaths, Map<String, BlobContent> newBlobs) {
		this.oldPaths = new HashSet<>();
		for (String oldPath: oldPaths) {
			String normalizedPath = GitUtils.normalizePath(oldPath);
			if (normalizedPath != null)
				this.oldPaths.add(normalizedPath);
			else
				throw new BlobEditException("Invalid old path: " + oldPath);
		}
		this.newBlobs = new HashMap<>();
		for (Map.Entry<String, BlobContent> entry: newBlobs.entrySet()) { 
			String normalizedPath = GitUtils.normalizePath(entry.getKey());
			if (normalizedPath != null)
				this.newBlobs.put(normalizedPath, entry.getValue());
			else
				throw new BlobEditException("Invalid new path: " + entry.getKey());
		}
	}

	public Set<String> getOldPaths() {
		return oldPaths;
	}

	public Map<String, BlobContent> getNewBlobs() {
		return newBlobs;
	}

View on GitHub (pinned to d44925c47c)

Solutions

  1. Pass only normalized relative paths (no leading '/', no '..' segments, non-empty) in oldPaths.
  2. Run GitUtils.normalizePath on each path yourself before constructing BlobEdits and skip/reject null results.
  3. Catch BlobEditException and report which path was invalid to the caller.
  4. Sanitize user-supplied file paths in the API/UI layer before building edit sets.

Example fix

// before
new BlobEdits(Set.of("/src/../../etc/passwd"), Map.of()); // throws
// after
String p = GitUtils.normalizePath("/src/../../etc/passwd"); // null -> reject earlier
if (p != null) new BlobEdits(Set.of(p), Map.of());
Defensive patterns

Strategy: validation

Validate before calling

Set<String> safe = new HashSet<>();
for (String p : oldPaths) {
    String n = GitUtils.normalizePath(p);
    if (n == null) throw new IllegalArgumentException("Invalid old path: " + p);
    safe.add(n);
}

Type guard

boolean isValidGitPath(String p) {
    return p != null && GitUtils.normalizePath(p) != null;
}

Try / catch

try {
    BlobEdits edits = new BlobEdits(oldPaths, newBlobs);
} catch (BlobEditException e) {
    // report invalid path to caller
}

Prevention

When it happens

Trigger: new BlobEdits(oldPaths, newBlobs) where oldPaths contains an empty string, a path like "/abs/path", "../escape", or any string GitUtils.normalizePath cannot reduce to a valid relative path.

Common situations: REST/API callers deleting or moving files with absolute or '..'-containing paths; UI/API input not sanitized before constructing edit sets; paths with redundant or malformed segments that normalize to null.

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


AI-assisted analysis of theonedev/onedev@d44925c47c (2026-09-06). Data as JSON: /api/errors/ccb6afc4f858650d. Report an issue: GitHub.