Skip to content

Don't fail on creation of sdist-vX/.git if it already exists#17825

Merged
konstin merged 1 commit intomainfrom
konsti/git-readonly
Feb 6, 2026
Merged

Don't fail on creation of sdist-vX/.git if it already exists#17825
konstin merged 1 commit intomainfrom
konsti/git-readonly

Conversation

@konstin
Copy link
Member

@konstin konstin commented Feb 3, 2026

Step 1 of N for readonly cache support. Moves the error message for LLM sandboxes from sdist-vX/.git to:

error: Could not acquire lock
    Caused by: Could not create temporary file
    Caused by: Read-only file system (os error 30  at path "/home/konsti/.cache/uv/.tmpfvc4gV"

@konstin konstin added the enhancement New feature or improvement to existing functionality label Feb 3, 2026
Comment on lines +453 to +456
fs_err::OpenOptions::new()
.create(true)
.write(true)
.open(phony_git)?;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this return a different error type with create(true) such that we can tell if it exists already without an extra syscall?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(per create(true) I don't think the title of this pull request is accurate, we shouldn't be recreating it already)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder why we even open it for writing if we don't write to it?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The information is not preserved: https://github.com/astral-sh/uv/pull/1782/changes

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I tried fs_err::OpenOptions::new().create_new(true).open(phony_git) and fs_err::OpenOptions::new().create(true).open(phony_git) but the error type isn't structured, we can't detect it reliably:

     [crates/uv-cache/src/lib.rs:455:9] output = Err(                                                                                
         Custom {                                                                                                                    
             kind: InvalidInput,                                                                                                     
             error: Error {                                                                                                          
                 kind: OpenFile,                                                                                                     
                 source: Custom {                                                                                                    
                     kind: InvalidInput,                                                                                             
                     error: "creating or truncating a file requires write or append access",                                         
                 },                                                                                                                  
                 path: "/home/konsti/.cache/uv/sdists-v9/.git",                                                                      
             },                                                                                                                      
         },                                                                                                                          
     )                                                                                                                               
     error: Failed to initialize cache at `/home/konsti/.cache/uv`                                                                   
       Caused by: failed to open file `/home/konsti/.cache/uv/sdists-v9/.git`: creating or truncating a file requires write or append
     access     

Copy link
Member Author

@konstin konstin Feb 3, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Turns out the reason is we fail if we don't have .write(true).

@zanieb
Copy link
Member

zanieb commented Feb 4, 2026

Unfortunately we can still hit the sandbox error in a race condition, which... seems rare but would be nice to avoid if we can. Could we just check if the file exists after we see an error then ignore the error if so? Also I presume if the file is missing we get a different error than if it exists but is read only?

@konstin konstin force-pushed the konsti/git-readonly branch from 42927fd to a014ae0 Compare February 4, 2026 15:01
@konstin
Copy link
Member Author

konstin commented Feb 4, 2026

If the cache directory doesn't exist you get earlier failures, we fail to create /home/konsti/.cache/uv or one of the other files. I'm afraid I don't have any better as how to avoid the extra check, the sandbox doesn't seem to return properly distinguished error messages. While the TOCTOU is a bad practice, the file is "touch only" (expect for cache clean), this doesn't seem like something that could create an observable bug.

No cache:

● Bash(uv-debug pip install tqdm -vv)                                                                                                                                                                                                                                                                                                                 
  ⎿  Error: Exit code 2                                                                                                                                                                                                                                                                                                                             
     DEBUG uv 0.9.29+4 (a014ae0a2 2026-02-04)                                                                                                                                                                                                                                                                                                         
     TRACE Error trace: Failed to initialize cache at `/home/konsti/.cache/uv`
                                                                                                                                                                                                                                                                                                                                                      
     Caused by:                                                                                                                                                                                                                                                                                                                                       
         failed to create directory `/home/konsti/.cache/uv`: Read-only file system (os error 30)                                                                                                                                                                                                                                                   
     error: Failed to initialize cache at `/home/konsti/.cache/uv`                                                                                                                                                                                                                                                                                    
       Caused by: failed to create directory `/home/konsti/.cache/uv`: Read-only file system (os error 30)       

Cache dir exists, but is empty:

● Bash(uv-debug pip install tqdm -vv)                                                                                                                                                                                                                                                                                                                 
  ⎿  Error: Exit code 2                                                                                                                                                                                                                                                                                                                             
     DEBUG uv 0.9.29+4 (a014ae0a2 2026-02-04)                                                                                                                                                                                                                                                                                                         
     TRACE Error trace: Failed to initialize cache at `/home/konsti/.cache/uv`
                                                                                                                                                                                                                                                                                                                                                      
     Caused by:                                                                                                                                                                                                                                                                                                                                       
         failed to open file `/home/konsti/.cache/uv/CACHEDIR.TAG`: Read-only file system (os error 30)                                                                                                                                                                                                                                             
     error: Failed to initialize cache at `/home/konsti/.cache/uv`                                                                                                                                                                                                                                                                                    
       Caused by: failed to open file `/home/konsti/.cache/uv/CACHEDIR.TAG`: Read-only file system (os error 30)  

Whether ~/.cache/uv/sdists-v9/.git exists doesn't seem to change the error message, I suspect :

● Bash(uv-debug pip install tqdm -vv)
  ⎿  Error: Exit code 2
     DEBUG uv 0.9.29+4 (a014ae0a2 2026-02-04)
     [crates/uv-cache/src/lib.rs:451:9] fs_err::OpenOptions::new().create(true).write(true).open(&phony_git) = Err(
         Custom {
             kind: ReadOnlyFilesystem,
             error: Error {
                 kind: OpenFile,
                 source: Os {
                     code: 30,
                     kind: ReadOnlyFilesystem,
                     message: "Read-only file system",
                 },
                 path: "/home/konsti/.cache/uv/sdists-v9/.git",
             },
         },
     )
     TRACE Error trace: Could not acquire lock
● Bash(uv-debug pip install tqdm -vv)                                                                                                                                                                                                                                                                                                                 
  ⎿  Error: Exit code 2                                                                                                                                                                                                                                                                                                                             
     DEBUG uv 0.9.29+4 (a014ae0a2 2026-02-04)                                                                                                                                                                                                                                                                                                         
     [crates/uv-cache/src/lib.rs:451:9] fs_err::OpenOptions::new().create(true).write(true).open(&phony_git) = Err(
         Custom {                                                                                                                                                                                                                                                                                                                                     
             kind: ReadOnlyFilesystem,                                                                                                                                                                                                                                                                                                                
             error: Error {                                                                                                                                                                                                                                                                                                                         
                 kind: OpenFile,                                                                                                                                                                                                                                                                                                                      
                 source: Os {                                                                                                                                                                                                                                                                                                                       
                     code: 30,                                                                                                                                                                                                                                                                                                                      
                     kind: ReadOnlyFilesystem,                                                                                                                                                                                                                                                                                                      
                     message: "Read-only file system",
                 },
                 path: "/home/konsti/.cache/uv/sdists-v9/.git",
             },
         },
     )

@zanieb
Copy link
Member

zanieb commented Feb 4, 2026

While the TOCTOU is a bad practice, the file is "touch only" (expect for cache clean), this doesn't seem like something that could create an observable bug.

The observable bug would be the same sandbox error that you're trying to fix.

Don't we have a ReadOnlyFilesystem error? Why can't we check that the file exists after we see that error instead of before?

@konstin
Copy link
Member Author

konstin commented Feb 5, 2026

Can you describe the order of events that you see for this TUCTOU bug? Does it introduce any additional failure paths?

@zanieb
Copy link
Member

zanieb commented Feb 5, 2026

No it doesn't introduce any new failure paths, but I don't understand the resistance to making the small change needed to avoid it? Do you want me to draft what I'm saying?

The TOCTOU is

A: Checks if the file exists -> no
B: Checks if the file exists -> no
B: Creates file
A: Fails with the existing error

Where B has cache write permissions (i.e., not sandboxed), and A is sandboxed.

@zanieb
Copy link
Member

zanieb commented Feb 5, 2026

e.g., why is 398a979 worse?

@konstin konstin force-pushed the konsti/git-readonly branch from a014ae0 to c720cf2 Compare February 6, 2026 10:28
@konstin
Copy link
Member Author

konstin commented Feb 6, 2026

I see, I don't think we can properly handle races between unsandboxed and sandboxed uv processes more generally (the sandboxed version fails or passes depending on the timing), but I agree that 398a979 is better code.

@konstin konstin force-pushed the konsti/git-readonly branch from c720cf2 to 88fb47a Compare February 6, 2026 10:50
@zanieb zanieb changed the title Don't recreate sdist-vX/.git if it already exists Don't fail on creation of sdist-vX/.git if it already exists Feb 6, 2026
Copy link
Member

@zanieb zanieb left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah I agree the situation will be hard to handle robustly

@konstin konstin merged commit 0dbeb4c into main Feb 6, 2026
53 checks passed
@konstin konstin deleted the konsti/git-readonly branch February 6, 2026 13:46
tmeijn pushed a commit to tmeijn/dotfiles that referenced this pull request Feb 15, 2026
This MR contains the following updates:

| Package | Update | Change |
|---|---|---|
| [uv](https://github.com/astral-sh/uv) | patch | `0.10.0` → `0.10.2` |

MR created with the help of [el-capitano/tools/renovate-bot](https://gitlab.com/el-capitano/tools/renovate-bot).

**Proposed changes to behavior should be submitted there as MRs.**

---

### Release Notes

<details>
<summary>astral-sh/uv (uv)</summary>

### [`v0.10.2`](https://github.com/astral-sh/uv/blob/HEAD/CHANGELOG.md#0102)

[Compare Source](astral-sh/uv@0.10.1...0.10.2)

Released on 2026-02-10.

##### Enhancements

- Deprecate unexpected ZIP compression methods ([#&#8203;17946](astral-sh/uv#17946))

##### Bug fixes

- Fix `cargo-install` failing due to missing `uv-test` dependency ([#&#8203;17954](astral-sh/uv#17954))

### [`v0.10.1`](https://github.com/astral-sh/uv/blob/HEAD/CHANGELOG.md#0101)

[Compare Source](astral-sh/uv@0.10.0...0.10.1)

Released on 2026-02-10.

##### Enhancements

- Don't panic on metadata read errors ([#&#8203;17904](astral-sh/uv#17904))
- Skip empty workspace members instead of failing ([#&#8203;17901](astral-sh/uv#17901))
- Don't fail creating a read-only `sdist-vX/.git` if it already exists ([#&#8203;17825](astral-sh/uv#17825))

##### Documentation

- Suggest `uv python update-shell` over `uv tool update-shell` in Python docs ([#&#8203;17941](astral-sh/uv#17941))

</details>

---

### Configuration

📅 **Schedule**: Branch creation - At any time (no schedule defined), Automerge - At any time (no schedule defined).

🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied.

♻ **Rebasing**: Whenever MR becomes conflicted, or you tick the rebase/retry checkbox.

🔕 **Ignore**: Close this MR and you won't be reminded about this update again.

---

 - [ ] <!-- rebase-check -->If you want to rebase/retry this MR, check this box

---

This MR has been generated by [Renovate Bot](https://github.com/renovatebot/renovate).
<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0Mi45Ny4zIiwidXBkYXRlZEluVmVyIjoiNDIuOTcuMyIsInRhcmdldEJyYW5jaCI6Im1haW4iLCJsYWJlbHMiOlsiUmVub3ZhdGUgQm90IiwiYXV0b21hdGlvbjpib3QtYXV0aG9yZWQiLCJkZXBlbmRlbmN5LXR5cGU6OnBhdGNoIl19-->
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or improvement to existing functionality

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants