file paths
path.combine
relative paths
absolute paths
C# programming

Path.Combine absolute with relative path strings

Interview Questions practice on Codemia

Over 8,000 real interview questions from top companies, searchable by company and role.

Browse interview questions

Introduction

Path.Combine in .NET is simple until one of the later path segments is already absolute. At that point, Path.Combine does not append to the earlier path. Instead, it discards the previous segments and returns a path rooted at the absolute argument. That behavior is correct, but it surprises a lot of people.

How Path.Combine Actually Works

Path.Combine is meant to join path segments safely, inserting directory separators where needed. The key rule is:

If any later argument is rooted, earlier parts are ignored from that point forward.

A small example:

csharp
1using System;
2using System.IO;
3
4public class Program
5{
6    public static void Main()
7    {
8        string basePath = @"C:\app\data";
9        string relative = @"reports\output.txt";
10        string absolute = @"D:\archive\output.txt";
11
12        Console.WriteLine(Path.Combine(basePath, relative));
13        Console.WriteLine(Path.Combine(basePath, absolute));
14    }
15}

The first call produces a combined path under C:\app\data. The second call returns the D:\archive\output.txt path because the second argument is rooted.

Why This Behavior Exists

Once .NET sees a rooted path, it assumes that segment defines the full path context and that the earlier base path is no longer relevant.

That is useful because it lets code safely handle both cases:

  • a user supplied a relative child path
  • a user supplied a complete absolute path

The function is not trying to "force append" absolute paths. It is trying to produce a valid path interpretation.

Check Rooted Paths Explicitly

If your logic depends on whether the second part is relative or absolute, check that first.

csharp
1using System;
2using System.IO;
3
4public static class PathHelper
5{
6    public static string CombineIfRelative(string basePath, string childPath)
7    {
8        if (Path.IsPathRooted(childPath))
9        {
10            return childPath;
11        }
12
13        return Path.Combine(basePath, childPath);
14    }
15}

This makes the rule explicit instead of relying on callers to know Path.Combine semantics.

Use Path.GetFullPath for Normalization

If you want to resolve a relative path against a base directory and then normalize the result, Path.GetFullPath is often the better tool.

csharp
1using System;
2using System.IO;
3
4public class Program
5{
6    public static void Main()
7    {
8        string basePath = @"C:\app\data";
9        string relative = @"..\logs\app.log";
10
11        string combined = Path.Combine(basePath, relative);
12        string full = Path.GetFullPath(combined);
13
14        Console.WriteLine(combined);
15        Console.WriteLine(full);
16    }
17}

This is especially useful when relative segments such as .. are involved.

Path.Combine Versus Path.Join

Newer .NET also includes Path.Join. It is useful for joining segments without some of the validation overhead of Path.Combine, but it does not change the main conceptual issue: rooted paths still need deliberate handling in your logic.

In most application code:

  • use Path.Combine when you want standard path semantics
  • use Path.Join when you care about lower-level joining behavior and already know what the inputs mean

Do not treat either as a generic string concatenation tool.

Cross-Platform Notes

On Windows, rooted paths often begin with a drive letter, such as C:\, or a UNC path. On Unix-like systems, a rooted path starts with /.

That means Path.IsPathRooted is the right cross-platform check:

csharp
1using System;
2using System.IO;
3
4Console.WriteLine(Path.IsPathRooted("/var/log/app.log"));
5Console.WriteLine(Path.IsPathRooted("logs/app.log"));

Avoid writing path rules that assume only Windows drive-letter syntax unless the application is truly Windows-only.

Safe Wrapper for User Input

If user input may be either relative or absolute, a small wrapper keeps the policy clear.

csharp
1using System;
2using System.IO;
3
4public static class StoragePathResolver
5{
6    public static string ResolvePath(string baseDirectory, string inputPath)
7    {
8        string result = Path.IsPathRooted(inputPath)
9            ? inputPath
10            : Path.Combine(baseDirectory, inputPath);
11
12        return Path.GetFullPath(result);
13    }
14}

This still needs security review if the input comes from untrusted users, because a normalized path can still escape a base directory if you allow it.

Common Pitfalls

One common mistake is assuming Path.Combine(basePath, absolutePath) appends the absolute path to the base path. It does not.

Another mistake is using plain string concatenation for file paths, which breaks separator handling and cross-platform behavior.

Developers also forget to normalize results when .. segments are present, leading to confusing relative path output.

Finally, some code accepts user input as a child path but forgets to reject rooted paths, which can break storage isolation rules.

Summary

  • 'Path.Combine ignores earlier segments once it encounters a rooted path.'
  • This behavior is intentional and usually correct.
  • Use Path.IsPathRooted when your code needs to treat absolute and relative inputs differently.
  • Use Path.GetFullPath to normalize combined paths.
  • Do not use path APIs as simple string concatenation helpers.

Related reading
Course
Intermediate
27 lessons
14 hours
OOD Fundamentals

Master object-oriented design from first principles, SOLID, design patterns, and classic interview problems with hands-on coding.

View the course
Track what you have practised

A free account saves your progress, solutions and study plan across every problem on Codemia.

Interview Questions practice on Codemia

Over 8,000 real interview questions from top companies, searchable by company and role.

Browse interview questions

All Rights Reserved.