Skip to content

Single file with filesystem-illegal name aborts entire download loop (Windows OS error 123) #25

Description

@dubadub

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.

Activity

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions