Skip to content

api: fix get_url() resolving relative paths against cwd instead of repo root - #11126

Open
Akshaay1 wants to merge 1 commit into
treeverse:mainfrom
Akshaay1:fix-get-url-subdir-cwd
Open

Akshaay1 wants to merge 1 commit into
treeverse:mainfrom
Akshaay1:fix-get-url-subdir-cwd

Conversation

@Akshaay1

Copy link
Copy Markdown

Problem

dvc.api.get_url() documents its path argument as "relative to the root of repo", but it raises OutputNotFoundError whenever the caller's current working directory is a subdirectory inside the DVC repo, even though the exact same call succeeds from the repo root or from outside the repo entirely.

Root Cause

Repo.get_data_index_entry() resolves path by calling self.dvcfs.from_os_path(path) followed by DVCFileSystem._get_key_from_relative(). For a plain relative string, from_os_path() passes it through unchanged, and _get_key_from_relative() then resolves it via self.abspath(path), which joins the path onto self.getcwd() — the filesystem's notion of "current directory", itself derived from the real OS process cwd mapped into repo-relative terms.

That's the right behavior for CLI commands like dvc add (where a path really is relative to wherever the user is standing), but get_url()'s contract says the path is relative to the repo root, not the caller's cwd. So when cwd is <repo_root>/subdir, a path like "bar.txt" gets resolved to "subdir/bar.txt" instead of "bar.txt", and the lookup in the data index fails.

Solution

In the subrepos branch of get_data_index_entry(), resolve path against self.root_dir directly (joining only when it isn't already absolute) and look up the index key with DVCFileSystem._get_key(), which is the existing cwd-independent counterpart to _get_key_from_relative(). This mirrors the else branch just below it, which already resolves non-subrepo paths against self.root_dir rather than cwd.

Testing

  • Test added: test_get_url_from_subdir in tests/func/api/test_data.py — creates a tracked file, chdirs into a subdirectory of the same repo, and asserts api.get_url() still returns the correct remote URL.
  • Tests run:
    • Confirmed the new test fails on unmodified main with dvc.exceptions.OutputNotFoundError: Unable to find DVC file with output 'bar' (verified via git stash), and passes with the fix.
    • pytest tests/func/api/test_data.py -v: 35 passed.
    • pytest tests/func/api/ tests/unit/fs/ tests/unit/repo/ tests/func/test_get_url.py -q (excluding one file that fails to collect due to an unrelated missing optional dvc-s3 dependency in this sandbox): 367 passed, 1 pre-existing unrelated failure (test_get_cloud_fs, same missing dvc-s3 dependency, reproduces identically on unmodified main).
    • ruff check / ruff format --check on the two changed files: clean (two pre-existing too-many-positional-arguments findings elsewhere in dvc/repo/__init__.py are unrelated to this change and present on unmodified main).

Related Issue

Closes #11029

…po root

dvc.api.get_url()'s `path` argument is documented as relative to the
root of `repo`, but Repo.get_data_index_entry() passed it through
DVCFileSystem._get_key_from_relative(), which resolves plain relative
paths against the filesystem's own getcwd() (itself derived from the
real process cwd). When the caller's current directory was a
subdirectory inside the repo, the path got resolved relative to that
subdirectory instead of the repo root, so a valid output could no
longer be found and get_url() raised OutputNotFoundError.

Resolve the path against self.root_dir before computing the index
key, using the existing cwd-independent DVCFileSystem._get_key(), so
the lookup matches the documented repo-root-relative contract
regardless of the caller's current directory.

Fixes treeverse#11029.
@github-project-automation github-project-automation Bot moved this to Backlog in DVC Oct 26, 2026
@CLAassistant

Copy link
Copy Markdown

CLA assistant check
Thank you for your submission! We really appreciate it. Like many open source projects, we ask that you sign our Contributor License Agreement before we can accept your contribution.
You have signed the CLA already but the status is still pending? Let us recheck it.

@codecov

codecov Bot commented Oct 26, 2026 •

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 90.98%. Comparing base (2431ec6) to head (2205948).
⚠️ Report is 213 commits behind head on main.

Additional details and impacted files
@@            Coverage Diff             @@
##             main   #11126      +/-   ##
==========================================
+ Coverage   90.68%   90.98%   +0.29%     
==========================================
  Files         504      505       +1     
  Lines       39795    41145    +1350     
  Branches     3141     3263     +122     
==========================================
+ Hits        36087    37434    +1347     
- Misses       3042     3072      +30     
+ Partials      666      639      -27     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@Akshaay1
Akshaay1 marked this pull request as ready for review October 31, 2026 09:37

This branch has not been deployed

No deployments
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.

dvc.api.get_url() throws error when working directory is a subdirectory of repo path

2 participants