Skip to content

Fix snow stage copy --recursive for vstage (snow://) paths#2786

Open
sfc-gh-moczko wants to merge 1 commit intomainfrom
fix/vstage-recursive-copy
Open

Fix snow stage copy --recursive for vstage (snow://) paths#2786
sfc-gh-moczko wants to merge 1 commit intomainfrom
fix/vstage-recursive-copy

Conversation

@sfc-gh-moczko
Copy link
Collaborator

@sfc-gh-moczko sfc-gh-moczko commented Feb 26, 2026

Summary

Fixes two bugs that caused snow stage copy --recursive to fail when downloading from vstage (snow://) paths, particularly DCM deployment stages like snow://project/.../deployments/DEPLOYMENT$1/.

  • Bug 1 — iter_stage() loses snow:// prefix: When ls returns plain relative paths (e.g., deployments/DEPLOYMENT$1/manifest.yml), build_path() misinterprets them as @-prefixed stage paths, generating invalid SQL (get @deployments/... instead of get 'snow://project/...'). Fixed by adding a vstage-aware branch that reconstructs full paths via stage_path.root_path() / file["name"].

  • Bug 2 — StagePath.relative_to() is case-sensitive: Snowflake normalizes unquoted identifiers to lowercase in ls output (DEPLOYMENT$1 becomes deployment$1), but PurePosixPath.relative_to() is case-sensitive, causing ValueError when computing local directory structure. Fixed with case-insensitive part-by-part comparison.

Files changed

File Change
src/snowflake/cli/_plugins/stage/manager.py 2-line elif branch in iter_stage() for snow:// paths
src/snowflake/cli/api/stage_path.py Replaced relative_to() with case-insensitive implementation
tests/stage/test_stage.py 4 new parametrized test cases across 2 test functions
tests/stage/test_stage_path.py 8 new parametrized test cases across 3 test functions

Test plan

  • New unit tests reproduce both bugs (5 failures before fix, 0 after)
  • Full stage test suite passes (327 passed, 50 snapshots)
  • All pre-commit hooks pass (ruff, black, mypy, codespell)
  • Manual verification against real DCM project on Snowflake (7 files downloaded with correct directory structure)
  • CI passes

@sfc-gh-moczko sfc-gh-moczko requested a review from a team as a code owner February 26, 2026 03:41
Two bugs prevented recursive copy from working with vstage paths
(e.g., `snow://project/.../deployments/DEPLOYMENT$1/`):

1. `iter_stage()` lost the `snow://` prefix when reconstructing file
   paths from `ls` output. Snowflake's `ls` returns plain relative
   paths (e.g., `deployments/DEPLOYMENT$1/manifest.yml`) without the
   `snow://` prefix. The existing code passed these to `build_path()`,
   which treated them as `@`-prefixed stage paths, producing invalid
   SQL like `get @deployments/DEPLOYMENT$1/manifest.yml ...` instead
   of `get 'snow://project/.../manifest.yml' ...`.

   Fix: Add a vstage-aware branch in `iter_stage()` that reconstructs
   full paths via `stage_path.root_path() / file["name"]` when the
   stage path starts with `snow://`.

2. `StagePath.relative_to()` used `PurePosixPath.relative_to()` which
   is case-sensitive. Snowflake normalizes unquoted identifiers to
   lowercase in `ls` output (e.g., `DEPLOYMENT$1` becomes
   `deployment$1`), causing `ValueError` when computing relative paths
   for local directory structure during recursive download.

   Fix: Replace with case-insensitive part-by-part comparison that
   preserves original casing in the returned relative path.

Verified against a real DCM project on Snowflake -- 7 files downloaded
successfully with correct directory structure preserved.

.... Generated with [Cortex Code](https://docs.snowflake.com/en/user-guide/cortex-code/cortex-code)

Co-Authored-By: Cortex Code <[email protected]>
@sfc-gh-moczko sfc-gh-moczko force-pushed the fix/vstage-recursive-copy branch from de5191c to 926d6a8 Compare February 26, 2026 15:33
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.

1 participant