Skip to content

AddDefaultProtoPaths fails when protoc added to PATH with symlink on Windows #25529

@LittleBoxOfSunshine

Description

@LittleBoxOfSunshine

What version of protobuf and what language are you using?
Version: main/v3.6.0/v3.5.0 etc. (NOTE: please try updating to the latest version of protoc/runtime possible beforehand to attempt to resolve your problem)
Language: C++/Java/Python/C#/Ruby/PHP/Objective-C/Javascript

v33.4; Rust originally, minimal repro here with C++

What operating system (Linux, Windows, ...) and version?

Windows

What runtime / compiler are you using (e.g., python version or gcc version)

protoc --version
libprotoc 33.4

What did you do?
Steps to reproduce the behavior:

  1. On Windows: Install protoc, add to the system PATH with a symbolic link. Ensure it is placed in an arbitrary location that isn't sharing current directory or parent directory with protoc.exe
  2. Compile a minimal proto that references a bundled file, without additional include dirs provided:
syntax = "proto3";

import "google/protobuf/timestamp.proto";

package fake;

service FooService {
  rpc Foo(FooMessage) returns (FooResult);
}

message FooMessage {
  bytes payload = 1;
  // Validates that the bundled includes are available
  google.protobuf.Timestamp submit_time = 2;
}

message FooResult {
  string message = 1;
}

using the command:

protoc .\src\fake-crate\protos\foo.proto --cpp_out temp

  1. Remove the symlink and add protoc.exe parent direcotry directly to PATH. Run the same command, observe it now passes.

What did you expect to see

Protoc finds the bundled definition google/protobuf/timestamp.proto and successfully compiles

What did you see instead?

google/protobuf/timestamp.proto: File not found.
src/fake-crate/protos/foo.proto:3:1: Import "google/protobuf/timestamp.proto" was not found or had errors.
src/fake-crate/protos/foo.proto:14:3: "google.protobuf.Timestamp" is not defined.

Make sure you include information that can help us debug (full error message, exception listing, stack trace, logs).

Anything else we should know about your project / environment

I originally encountered this because of a WinGet bug that was improperly tagging the package leading to a symlink being used. I raised a separate issue there that has unblocked us, but sincethe functions used on other platforms will resolve symlinks, I believe this is an oversight on the Windows side:

  • Mac: realpath
  • Else: readlink

The Windows implementation is using GetModuleFileNameA, which isn't resolving the symlink. Instead, that result should probably then be passed to GetFinalPathNameByHandleA in order to resolve it.

From repro machine:

PS C:\Users\chhenk> ls ~\AppData\Local\Microsoft\WinGet\Links

    Directory: C:\Users\chhenk\AppData\Local\Microsoft\WinGet\Links

Mode                 LastWriteTime         Length Name
----                 -------------         ------ ----
la---           1/26/2026  5:32 PM              0 protoc.exe ->
                                                  C:\Users\chhenk\AppData\Local\Microsoft\WinGet\Packages\Google.Protobuf_Microsoft.Winget.Source_8wekyb3d8bbwe\bin\protoc.exe
PS C:\Users\chhenk> $env:PATH -split ';' | Where-Object { $_ -match 'winget' }
C:\Users\chhenk\AppData\Local\Microsoft\WinGet\Links

Whereas when I have a direct reference in the PATH like so, it works as expected:

$env:PATH -split ';' | Where-Object { $_ -match 'winget' }
C:\Users\chhenk\AppData\Local\Microsoft\WinGet\Packages\Google.Protobuf_Microsoft.Winget.Source_8wekyb3d8bbwe\bin

Metadata

Metadata

Assignees

No one assigned

    Labels

    untriagedauto added to all issues by default when created.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions