Skip to content

Local -OutputPath is broken on Linux: hardcoded backslash makes checkpoint paths unopenable #84

Description

@sambetts

Local -OutputPath is broken on Linux: hardcoded '\' separator makes checkpoint paths unopenable

Repo: microsoft/PAX
Version: v1.11.15

Summary

When -OutputPath is a local path, PAX normalises it to directory form by appending a hardcoded backslash:

PAX_Purview_Audit_Log_Processor_v1.11.15.ps1, lines 7240 and 7255:

if (-not $OutputPath.EndsWith('\') -and -not $OutputPath.EndsWith('/')) {
    $OutputPath = $OutputPath + '\'
}

On Linux, \ is a legal filename character, not a separator. Passing -OutputPath /tmp/pax-output therefore yields /tmp/pax-output\, and every derived path is built underneath a directory that doesn't exist:

G-9: Failed to acquire checkpoint lock at /tmp/pax-output\/.pax_checkpoint_20260826_103115.json.lock:
Exception calling "Open" with "4" argument(s): "Could not find a part of the path
'/tmp/pax-output\/.pax_checkpoint_20260826_103115.json.lock'." Another process may have raced in.

The run aborts before any data is fetched.

Why the error is misleading

It is reported as a checkpoint lock contention problem — "Another process may have raced in" — which sends you looking for a stale lock or a concurrent run. The actual fault is the path separator, and the backslash is easy to miss inside a long path string.

Why it isn't caught by the shipped container guidance

fabric_resources/ documents running PAX in an Azure Container Apps Job, i.e. on Linux — but always with -OutputPath pointing at a SharePoint or OneLake URL. That takes the remote-output branch, which builds the scratch directory correctly:

line 7447-7448:

$sep = [System.IO.Path]::DirectorySeparatorChar
if (-not $OutputPath.EndsWith($sep)) { $OutputPath = $OutputPath + $sep }

So the bug only bites when a Linux host stages output locally — e.g. exporting to a local directory and then uploading, or writing to a mounted volume. Both are reasonable containerised patterns.

Reproduction

Linux container (mcr.microsoft.com/powershell:lts-7.4-ubuntu-22.04, the base used by fabric_resources/Dockerfile/PAX.Dockerfile):

pwsh -File PAX_Purview_Audit_Log_Processor_v1.11.15.ps1 \
  -Rollup -IncludeUserInfo -Auth AppRegistration \
  -TenantId <t> -ClientId <c> -ClientSecret <s> \
  -StartDate 2026-08-23 -EndDate 2026-08-27 \
  -OutputPath /tmp/pax-output \
  -OutputPathUserInfo /tmp/pax-output \
  -OutputPathLog /tmp/pax-output

Fails immediately with the G-9 error above.

Workaround

Pass a trailing separator on every -OutputPath*, since the append is skipped when one is already present:

-OutputPath /tmp/pax-output/

With that single change the same command runs to completion (62 partitions, rollup CSVs written).

Suggested fix

Use [System.IO.Path]::DirectorySeparatorChar at lines 7240 and 7255, matching what line 7448 already does. Optionally also accept / as a separator on Windows, which .NET handles natively.

Activity

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

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions