Skip to content

Strip trailing slash before DFS GetProperties (fixes OneLake 403) (backport #174)#177

Merged
benfleis merged 5 commits into
duckdb:v1.5-variegatafrom
benfleis:fix/onelake-dfs-trailing-slash--v1.5
Jul 13, 2026
Merged

Strip trailing slash before DFS GetProperties (fixes OneLake 403) (backport #174)#177
benfleis merged 5 commits into
duckdb:v1.5-variegatafrom
benfleis:fix/onelake-dfs-trailing-slash--v1.5

Conversation

@benfleis

Copy link
Copy Markdown
Member

(backport #174), thanks @djouallah

Problem

On the DFS filesystem, CreateHandle passes parsed_url.path straight into GetFileClient(...), so a trailing / ends up on the wire in the subsequent GetProperties() call. A trailing slash is only a directory hint, not part of the resource name.

OneLake's DFS endpoint (*.dfs.fabric.microsoft.com) rejects a GetProperties on a trailing-slash path with 403 AuthenticationFailed / Forbidden, while the identical request without the slash returns 200. Because DirectoryExists, FileExists, and Glob (no-wildcard) all funnel through OpenFileCreateHandleLoadRemoteFileInfoGetProperties, any directory probe on OneLake fails.

This surfaces in practice as duckdb-delta partitioned writes failing: PhysicalCopyToFile probes the target table directory via DirectoryExists("…/Tables/dbo/<table>/"), producing:

IOException: AzureStorageFileSystem open file '…/Tables/dbo/<table>/' failed with code 'AuthenticationFailed', Reason Phrase: 'Forbidden'

Reproduces standalone, no write needed:

SELECT count(*) FROM glob('abfss://…@onelake.dfs.fabric.microsoft.com/…/<table>');   -- 200, works
SELECT count(*) FROM glob('abfss://…@onelake.dfs.fabric.microsoft.com/…/<table>/');  -- 403, fails

Fix

Strip a single trailing / from the path used to build the file client. info.path is left untouched, so the directory-marker detection in LoadRemoteFileInfo (StringUtil::EndsWith(afh.GetPath(), "/")) still works; only what is sent to the service changes. Real file keys never end in /, so reads/writes/Create are unaffected.

Note: only the DFS (abfss:///abfs://) filesystem is touched here since that's where OneLake lives. The Blob filesystem has the same pattern if parity is desired.

benfleis and others added 5 commits June 11, 2026 13:35
A trailing '/' is a directory hint, not part of the resource name, but it
was passed straight into GetFileClient(parsed_url.path). OneLake's DFS
endpoint rejects a GetProperties on a trailing-slash path with
403 AuthenticationFailed (the slash-less path returns 200), so any
DirectoryExists/FileExists/glob on a directory fails. This breaks e.g.
duckdb-delta partitioned writes, which probe the table directory.

Strip a single trailing slash from the path used to build the file client.
info.path is left untouched, so the directory-marker check in
LoadRemoteFileInfo still works.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@benfleis
benfleis merged commit 334798f into duckdb:v1.5-variegata Jul 13, 2026
18 checks passed
@benfleis

Copy link
Copy Markdown
Member Author

@djouallah this is the v1.5 variant of #174; it should be available in core_nightly for v1.5.4 in a couple hours.

@djouallah

Copy link
Copy Markdown
Contributor

@benfleis

The v1.5 cherry-pick dropped the call-site change — CreateHandle still passes parsed_url.path to GetFileClient, so the strip block is dead code and the 403 still repros on 334798f. Needs GetFileClient(file_path) like main. One-liner: https://github.com/duckdb/duckdb-azure/blob/v1.5-variegata/src/azure_dfs_filesystem.cpp (line ~174)

benfleis added a commit to benfleis/duckdb-azure that referenced this pull request Jul 14, 2026
benfleis added a commit that referenced this pull request Jul 14, 2026
@benfleis

Copy link
Copy Markdown
Member Author

@djouallah thanks for the catch, the fix is pushed out and will be pulled in from nightly.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants