Skip to content

MSVC does not support long paths inside Docker container #622

Closed

Description

@jdoubleu

Describe the bug
Apparently MSVC does not support long paths inside a Docker container. On the host, it works perfectly fine.

To Reproduce
I've prepared a minimal repo: https://github.com/jdoubleu/msvc-docker-bug
Steps to reproduce the behavior:

  1. clone the above repo
  2. run docker build -t msvc-docker-bug .

The Dockerfile should be self-explanatory.

Expected behavior
The second compilation from the Dockerfile should work just as fine as the first one.

The behavior should match the host environment, where MSVC does not have any issues working with long paths. Even when long path support has not been enabled system-wide.

Configuration:

  • Edition: Windows 11 Pro (10.0.22631 Build 22631)
  • Base Image being used: mcr.microsoft.com/windows/servercore:ltsc2022
  • Container engine: docker
  • Container Engine version: Docker version 27.5.1, build 9f9e405

Additional information:
Related issue: #361

Activity

  1. github-actions commented on Nov 6, 2025

    @github-actions

    Thank you for creating an Issue. Please note that GitHub is not an official channel for Microsoft support requests. To create an official support request, please open a ticket here. Microsoft and the GitHub Community strive to provide a best effort in answering questions and supporting Issues on GitHub.

  2. xlazom00 commented on Dec 3, 2025

    @xlazom00

    Is it woking on normal windows? As I don't think so. MSVC and msbuild has problem with long path and I also reported this issues on MS

  3. jdoubleu commented on Dec 6, 2025

    @jdoubleu
    Author

    Yes, it perfectly works fine on a normal Windows host. I've set the registry key at HKLM\SYSTEM\CurrentControlSet\Control\FileSystem in both cases.

  4. sureshbabu-msft commented on May 4, 2026

    @sureshbabu-msft

    Hi jdoubleu (@jdoubleu),

    Update on Long Path Support in Windows Containers

    Root Cause: The LongPathsEnabled registry setting is not being honoured inside Windows containers. This is a platform-level issue (related: #361). The same setup works correctly on the host OS, confirming this is not an MSVC bug.

    Workaround: Directory Junction

    Create a short-path junction to bypass the 260-char limit:

    RUN cmd /c mklink /J C:\short_include ${ENV:LONG_PATH}
    RUN C:\BuildTools\Common7\Tools\Launch-VsDevShell.ps1 -Arch amd64;
    cl.exe /std:c++latest /IC:\short_include C:\src\main.cpp

    Permanent Fix

    We've identified this as a credible bug and have escalated it internally for investigation. We'll update this thread as we make progress.

  5. microsoft-github-policy-service commented on Jun 4, 2026

    @microsoft-github-policy-service
    Contributor

    This issue has been open for 30 days with no updates.
    no assignees, please provide an update or close this issue.

  6. microsoft-github-policy-service commented on Jul 8, 2026

    @microsoft-github-policy-service
    Contributor

    This issue has been open for 30 days with no updates.
    no assignees, please provide an update or close this issue.

  7. microsoft-github-policy-service commented on Aug 11, 2026

    @microsoft-github-policy-service
    Contributor

    This issue has been open for 30 days with no updates.
    no assignees, please provide an update or close this issue.

  8. lemeurherve commented on Aug 11, 2026

    @lemeurherve

    sureshbabu-msft: any progress to share by any chance?

  9. microsoft-github-policy-service commented on Sep 11, 2026

    @microsoft-github-policy-service
    Contributor

    This issue has been open for 30 days with no updates.
    no assignees, please provide an update or close this issue.

  10. ramesh-ramn commented on Oct 9, 2026

    @ramesh-ramn
    Collaborator

    Hi jdoubleu (@jdoubleu), thank you for the clear repro repo.

    I investigated the issue you raised. Here is what I found:

    • Windows containers do honor the LongPathsEnabled setting.
    • I see the same behavior on a normal Windows machine as in a container: the build fails in both.
    • cl.exe is not long path aware. Its manifest does not declare longPathAware, so it cannot use long paths even when LongPathsEnabled is 1.

    The details are below. Every check uses only standard tools (mt.exe, findstr, cmd, PowerShell), so you can run them yourself.

    Summary

    • cl.exe fails with fatal error C1083: Cannot open include file when the full path to the included file is longer than 260 characters. In your repo the include directory path is 255 characters and the full path to example.hpp is 267 characters.
    • This happens inside a container and on a normal Windows machine, with LongPathsEnabled set to either 1 or 0.
    • The reason: cl.exe does not declare long path support (longPathAware) in its application manifest. Windows allows a program to use long paths only when both of these are true (Microsoft docs):
      1. LongPathsEnabled is set to 1, and
      2. the program declares longPathAware in its manifest.
    • Inside the container, programs that do declare longPathAware (PowerShell and cmd.exe) can open the same long path when the setting is 1, and cannot when it is 0. So the container follows the setting.
    • In my testing, cl.exe doesn't advertise long path support. There is an open issue about this: Developer Community issue 10221576.
    • Workarounds that work today: a directory junction (tested) or a shorter source path (tested); see Workarounds. Neither needs LongPathsEnabled changed. A subst drive should also work, but I did not test it.

    How Windows decides whether a program can use long paths

    Turning on LongPathsEnabled is not enough by itself. Each program must also opt in through its manifest. This is documented in
    Maximum Path Length Limitation (see "Enable long paths in Windows 10, version 1607, and later").

    LongPathsEnabled Program declares longPathAware Long paths work?
    0 No No
    0 Yes No
    1 No No (this is cl.exe)
    1 Yes Yes (for example PowerShell and cmd.exe)

    Each program reads the setting when it starts, so inside a container the container's own setting is what counts. Your Dockerfile sets it correctly.

    How to check a program's manifest

    A program's manifest is stored inside the .exe file. mt.exe (the Microsoft Manifest Tool) can extract it. mt.exe is part of the Windows SDK, which the Visual Studio Build Tools install with the C++ workload when --includeRecommended is used, as in your Dockerfile. In a Developer Command Prompt it is already on the PATH. Otherwise it is under C:\Program Files (x86)\Windows Kits\10\bin\<SDK version>\x64\mt.exe.

    mt.exe -nologo -inputresource:"C:\path\to\program.exe";#1 -out:program.manifest
    findstr /i longPathAware program.manifest
    

    -inputresource reads the manifest stored as a resource inside the file (Mt.exe). ;#1 selects resource ID 1, the manifest Windows uses for an .exe (Using Side-by-Side Assemblies as a Resource).

    If findstr prints a line containing longPathAware>true, the program opts in. If it prints nothing, the program does not opt in, and LongPathsEnabled has no effect on it.

    What I tested

    Setup:

    • Host: Windows 11 22H2 with Docker, Hyper-V isolation (the default on Windows 11).
    • Image: mcr.microsoft.com/windows/servercore:ltsc2022.
    • Compiler: MSVC 19.44.35229 from VS 2022 Build Tools 17.14.41 (what your Dockerfile installed when I ran it).
    • Manifest tool: mt.exe from Windows SDK 10.0.26100, installed with the Build Tools.

    I ran three sets of tests:

    1. Your Dockerfile, with mt.exe checks added, and LongPathsEnabled=1 as in your repo.
    2. A test Dockerfile of my own, based on yours, that separates container behavior from compiler behavior. I ran it twice: once with LongPathsEnabled=1 and once with 0 (the servercore default).
    3. The same Windows 11 machine with no container. I installed the same Build Tools directly on it and ran the same compiles, once with LongPathsEnabled=0 and once with 1.

    In your Dockerfile the long include directory is 255 characters, and the full path to example.hpp inside it is 267 characters. My test Dockerfile uses a 280-character directory, so the full path to example.hpp is 292 characters.

    Results

    1. Your Dockerfile. The long /I build fails with C1083 on example.hpp, exactly as you reported. mt.exe shows that cl.exe has no longPathAware entry.

    2. Test Dockerfile (container).

    Check LongPathsEnabled=1 LongPathsEnabled=0
    PowerShell reads a file at the long path Works Fails
    cmd.exe type reads a file at the long path Works Fails
    cl.exe with a short /I path Works Works
    cl.exe with /I pointing at a junction (C:\s) to the long folder Works Works
    cl.exe with the long /I path C1083 C1083

    mt.exe results inside the container, the same in both runs:

    Program Declares longPathAware?
    powershell.exe Yes
    cmd.exe Yes
    cl.exe 19.44.35229 No
    findstr.exe No

    The programs whose manifest declares longPathAware (PowerShell and cmd.exe) follow the LongPathsEnabled setting. The cl.exe manifest does not declare it, so cl.exe fails either way.

    3. Same machine, no container.

    Check LongPathsEnabled=0 LongPathsEnabled=1
    cl.exe with a short /I path Works Works
    cl.exe with the long /I path (your 255-character folder) C1083 C1083

    mt.exe gave the same manifest results as in the container. So cl.exe behaves the same with and without a container.

    Other checks. Earlier in the investigation I also ran the test Dockerfile with process isolation on Windows Server 2022, and got the same results. On a newer Windows 11 machine with no container and LongPathsEnabled=1, MSVC 19.51 also failed with C1083 on the long /I path, so newer compilers behave the same way.

    How to verify in a container

    These are a trimmed version of the steps I added to your Dockerfile, after the LONG_PATH folder is created and before your build steps. They use VsDevCmd.bat, which puts mt.exe on the PATH and sets VCToolsInstallDir.

    SHELL ["cmd.exe", "/S", "/V:ON", "/C"]
    
    # Check 1: which programs opt in to long paths?
    RUN call C:\BuildTools\Common7\Tools\VsDevCmd.bat -arch=amd64 -host_arch=amd64 -no_logo && `
        echo === cmd.exe === && `
        mt.exe -nologo -inputresource:"%WINDIR%\System32\cmd.exe";#1 -out:C:\TEMP\cmd.manifest && `
        (findstr /i longPathAware C:\TEMP\cmd.manifest || echo no longPathAware entry) && `
        echo === cl.exe === && `
        mt.exe -nologo -inputresource:"!VCToolsInstallDir!bin\Hostx64\x64\cl.exe";#1 -out:C:\TEMP\cl.manifest && `
        (findstr /i longPathAware C:\TEMP\cl.manifest || echo no longPathAware entry)
    
    # Check 2: the container honors LongPathsEnabled.
    ADD example.hpp ${LONG_PATH}
    RUN type %LONG_PATH%\example.hpp
    
    SHELL ["powershell.exe", "-NoLogo", "-ExecutionPolicy", "Bypass"]
    

    Each RUN line is one cmd command, and cmd fills in %VAR% before any of it runs. /V:ON makes !VCToolsInstallDir! take its value after VsDevCmd.bat has set it. The backtick line continuations need # escape=` at the top of the Dockerfile, which yours already has.

    Expected output: Check 1 prints a longPathAware line for cmd.exe and no longPathAware entry for cl.exe. Check 2 prints the contents of example.hpp, because cmd.exe opts in and your Dockerfile sets LongPathsEnabled=1. If you remove the registry update that sets LongPathsEnabled, Check 2 fails. Your long /I build still fails afterwards in both cases.

    Workarounds

    Each of these keeps the paths that cl.exe sees under 260 characters:

    1. Directory junction (tested, works in containers). A junction is a short folder name that points to the long folder. These two steps replace your long /I build step and use your Dockerfile's PowerShell SHELL:
      RUN cmd /c mklink /J C:\inc "\\?\${ENV:LONG_PATH}"
      RUN C:\BuildTools\Common7\Tools\Launch-VsDevShell.ps1 -Arch amd64; `
          cl.exe /std:c++latest /IC:\inc C:\src\main.cpp
      
      The junction shortens only the include path; for output paths, see item 4.
    2. Shorter source path (tested: the short /I builds above). Use a short WORKDIR or clone location such as C:\s.
    3. subst drive (not tested). subst X: <long folder> makes a drive letter that points to a folder; then use /IX:\. A subst drive lasts only for the current session, so create it in the same RUN step as the build.
    4. Keep output paths short too. Object files, PDBs and build folders (/Fo, /Fd) are also subject to the limit.

    Also note that a single folder or file name cannot be longer than 255 characters on NTFS, even with long paths enabled.

    Related compiler and linker errors you may see with long paths:
    C1083,
    C1081,
    LNK1104.

    Next steps

    • There is an open issue for MSVC long path support: Developer Community issue 10221576. Its title says 255 characters, but the failure is the 260-character limit that applies to programs without longPathAware. Please upvote it and add your scenario. That is the best place to follow a compiler fix.
    • Based on these results, I don't see a change needed in Windows containers. If you find a program that declares longPathAware and still cannot use long paths inside a container, please share the details here.

    Thanks again for the detailed report.

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingtriageNew and needs attention

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions