cooklang / cooklang/cooklang-sync
Single file with filesystem-illegal name aborts entire download loop (Windows OS error 123)
- Dominant language
- Rust
- Stars
- 13
- Forks
- 4
- Avg merge
- 3m
- Merged PRs (30d)
- 1
Description
## Summary
A single file whose name contains characters that are illegal on the target
filesystem aborts the **entire** download loop, permanently blocking sync of
the whole library on that device until the offending record is changed
server-side.
## Impact
Filenames are validated by neither the server (`/metadata/commit`) nor the
client on download. A file created on a permissive filesystem (e.g. Linux/
Android, which allow `"`, `:`, `|`, etc.) is happily stored and listed by the
server. When another device on a stricter filesystem (Windows forbids
`< > : " / \ | ? *`, trailing dots/spaces, reserved names like `CON`) tries to
download it, `File::create` fails and the error propagates all the way up:
- `check_download_once` returns the IO error (`syncer.rs`, the `chunker.save(...)`
call in the post-download write loop)
- `download_loop` maps it to `SyncError::Unknown("Check download failed: ...")`
and returns, killing the loop
On Windows this surfaces to users as:
```
Check download failed: IO error in file ... OS error 123
```
(`ERROR_INVALID_NAME`). Because the same record is re-fetched on every retry,
the loop never makes progress — one bad filename bricks sync for all files,
not just the one.
## Steps to reproduce
1. On Linux/Android, create a recipe with a Windows-illegal character in the
name, e.g. `Folder/Example "quoted" name.cook`, and let it sync up.
2. On a Windows client, start sync.
3. Observe sync abort with `Check download failed: ... OS error 123`; no files
download, including unrelated ones.
## Suggested fixes
1. **Client resilience (most important):** a single file's IO error in
`check_download_once` should not abort the loop. Log a warning, skip that
file, continue with the rest, and surface a non-fatal status to the user.
This downgrades "library bricked" to "one recipe missing."
2. **Server-side validation at commit:** reject or flag paths containing
characters that are invalid on common filesystems. This is the only choke
point that protects every client at once.
3. Avoid silently sanitizing/renaming on download — the local indexer would
treat the renamed file as new and re-upload it, creating a duplicate loop.
Skip-and-surface is safer than rename.
## Notes
Recovery today requires a server-side DB edit: insert a new record renaming the
path to a valid name (reusing the existing `chunk_ids`) plus a tombstone for the
old path, so all devices converge. The `/list` endpoint already returns only the
latest record per path, so this propagates cleanly — but it shouldn't require
manual intervention.
Contributor guide
No contributing guide indexed for this repository
Research direction
Start by reading check_download_once and the chunker.save(...) call in syncer.rs, then trace how download_loop maps its errors. Review the /metadata/commit and /list behavior described in the issue. Done means an invalid filename no longer aborts synchronization for unrelated files, while the affected file is skipped and surfaced as a non-fatal status.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- rust
- Domain
- backend, distributed-systems, operating-systems
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 68/100