Skip to content

Paths: the parent of a one-segment relative path (or the directory of a bare file name) is "", so AsAbsolute() throws and IsDirectory is false #502

Closed

Description

@matt-edmondson

What's wrong

Several getters return the empty path to mean "the starting directory":

  • RelativeDirectoryPath.Parent (Semantics.Paths/Implementations/RelativeDirectoryPath.cs:64) runs string.Join(separator, segments, 0, 0) for a single-segment path, which gives "". The XML doc says so: "an empty path for a single-segment path".
  • RelativeFilePath.RelativeDirectoryPath (Implementations/RelativeFilePath.cs:39) and the directory getter in SemanticFilePath.cs (~L114) use Path.GetDirectoryName("a.txt") ?? "", which also gives "".

The type treats "" as the starting directory (Depth docs, ComputeParent), but the operations pass it straight to the BCL, which rejects it:

  • Path.GetFullPath("") throws ArgumentException. This hits RelativeDirectoryPath.AsAbsolute() (~L192), IRelativePath.AsAbsolute() (~L219) and DirectoryPath.cs:53.
  • Directory.Exists("") is false, so IsDirectory is wrong (SemanticPath.cs:53, SemanticDirectoryPath.cs:35).
  • On netstandard2.0, PathPolyfill.GetFullPath("", base) (Polyfills.cs:146) throws "Path cannot be empty." On net8+, Path.GetFullPath("", base) returns base. The same call behaves differently depending on the target framework.

Normalize() already writes the starting directory as ".", so Parent disagrees with it.

Observed (net10.0 build)

  • RelativeDirectoryPath.Create("src").Parent is '':
    • .AsAbsolute() throws ArgumentException: The value cannot be an empty string. (Parameter 'path').
    • .IsDirectory is False.
    • .GetContents() is empty, even though the working directory has contents.
  • RelativeFilePath.Create("a.txt").RelativeDirectoryPath.AsAbsolute() throws the same way.

The reasonable call file.RelativeDirectoryPath.AsAbsolute() crashes for any file in the current directory.

Suggested fix

  • Have Parent return "." when no segment is left, matching Normalize, and update its XML doc.
  • Map an empty GetDirectoryName result to "." in the relative directory-of-file getters.
  • Make PathPolyfill.GetFullPath return basePath for an empty path, matching the BCL on net8+.

Acceptance criteria

  • RelativeDirectoryPath.Create("src").Parent.AsAbsolute() equals the current directory, and IsDirectory is true.
  • RelativeFilePath.Create("a.txt").RelativeDirectoryPath.AsAbsolute() equals the current directory.
  • AsAbsolute(baseDir) on the starting directory returns baseDir on every target framework.

Activity

  1. matt-edmondson commented on Oct 30, 2026

    @matt-edmondson
    ContributorAuthor

    Triage


    Generated by Claude Code

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Labels

bugSomething isn't working

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions