fix(upload,sync): surface partial upload failures instead of silently swallowing them#4
Merged
Merged
Conversation
… swallowing them Root-caused a "why did upload folder skip a file with no error" report: per-file failures in `upload folder` were only ever reported via `pb.println`, and indicatif fully hides a ProgressBar's draw target (including println output, not just the animated bar) whenever stderr isn't a real terminal. Any piped/scripted/CI/non-interactive run of `upload folder` therefore reported blanket success and exit 0 no matter how many files failed, with zero trace of what happened. Confirmed via a live repro: stdout and stderr both came back completely empty for a run where a file demonstrably failed to upload. `upload folder` now tracks failures independently of the progress bar and returns an error naming every failed file and its reason, causing a non-zero exit. `sync up`/`sync down` (and `download folder`, which reuses `sync_down`) already tracked failures in a `Summary` independent of the bar, but still always returned `Ok(())`; they now exit non-zero too when `failed > 0`, without double-printing (the existing summary output already reports it). Separately, confirmed (and initially misdiagnosed) two things while investigating: Internxt's free/legacy plans reject 0-byte files with HTTP 402, and `upload folder`'s local scan silently skipped 0-byte files before this fix — which, per og's own `local-filesystem.service.ts` (`stats.isFile() && stats.size > 0`), mirrors the reference CLI exactly, not a divergence. Per explicit request, changed that default: empty files are now included by default in both `upload folder` and `sync up` (and left to fail/succeed based on the account's plan, now visibly), with a new `--exclude-empty-files` flag to restore the old skip-silently behavior for accounts where the 402 is expected and not worth reporting. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019s9ZyfTYiVG8nHemEWFdEM
Bebbssos
added a commit
that referenced
this pull request
Jul 22, 2026
… bailout internxt-core 0.1.2 (released, includes PR #4) makes create_folder_with_retry look up and return the existing folder's uuid on a name collision instead of giving up, so the common case is now fully transparent: a colliding folder (and its contents) upload normally instead of being skipped. Ok(None) is now only the rarer case (lookup miss on a race, or exhausted non-conflict retries) — treat it the same as any other per-item failure: track it in the shared `failed` list (moved up so both the folder and file loops share it) and skip just that subtree, instead of aborting the whole upload via the old `folder_map.is_empty()` bailout (removed). A missing parent (because its own folder failed) is now also tracked in `failed` rather than just a status line, so it's no longer invisible in the final summary/exit code either. Live-verified: re-uploading an identical tree (folder-name collision on every level) now succeeds at the folder level ("Folder ready: x" for all three, no skipping) and only the genuinely-conflicting files fail with a clear 409 each — exactly the behavior the original bug report wanted, instead of the old unconditional "Failed to create folders, cannot upload files" abort. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
upload folderwere only ever reported viapb.println, and indicatif fully hides a ProgressBar's draw target (includingprintlnoutput, not just the animated bar) whenever stderr isn't a real terminal — so any piped/scripted/CI run reported blanket success and exit 0 no matter how many files failed. Confirmed live: stdout and stderr both came back completely empty on a run where a file demonstrably failed.upload foldernow tracks failures independently of the progress bar and returns an error naming every failed file + reason, causing a non-zero exit.sync up/sync down(anddownload folder, which reusessync_down) already tracked failures in aSummaryindependent of the bar, but always returnedOk(())regardless; they now exit non-zero too whenfailed > 0.upload folder's local scan silently skipped 0-byte files before this fix — which mirrors og's ownlocal-filesystem.service.ts(stats.isFile() && stats.size > 0) exactly, not a divergence. Per explicit request, flipped that default: empty files are now included by default in bothupload folderandsync up(left to fail/succeed visibly per the account's plan), with a new--exclude-empty-filesflag to restore the old skip-silently behavior.Test plan
cargo build --all-features,cargo clippy --all-features --all-targets,cargo testall cleanupload folderon a 0-byte file now exits 1 with"1 of 2 file(s) failed to upload ... HTTP 402 Payment Required..."on stderr--exclude-empty-filesrestores the old clean skip / exit 0🤖 Generated with Claude Code
https://claude.ai/code/session_019s9ZyfTYiVG8nHemEWFdEM