See what your Nextcloud sync is actually doing on macOS.
With virtual files enabled, a Nextcloud folder always looks complete. It isn't. Every file is in one of three states, and the Finder shows all three identically:
| State | Where the bytes are | Safe? |
|---|---|---|
| Cloud-only placeholder | Server only | Yes — the server has it |
| Materialized and synced | Both | Yes — two copies |
| Never uploaded | This Mac only | No — one copy, nowhere else |
All three report their full size to ls, to the Finder, and to every backup tool.
A folder can show 40 GB while holding 6 GB of real data — and a file you believe
is "in the cloud" may exist only on the disk in front of you.
Worse, sync can stop without telling you. macOS retries a failed upload with an
exponential backoff and eventually marks it next: never — it has given up.
There is no error dialog. The folder still looks complete.
ncstatus reads Apple's File Provider daemon, which is what actually schedules
the sync, and reports what it knows. Because it asks the OS rather than scanning
your files, the whole report takes about two seconds.
For the File Provider (virtual files) client only. Modern Nextcloud clients on macOS sync through Apple's File Provider framework, with your files under
~/Library/CloudStorage/. If you use the older sync method — an ordinary folder anywhere else on disk — this tool has nothing to read and will not report on it.
$ ncstatus
Nextcloud STUCK /Users/you/Library/CloudStorage/Nextcloud-cloud.example.com-you
no transfer in progress
NOT ON SERVER 3 files 1.42 GB these exist ONLY on this Mac
1.31 GB 2 Projects/RenderAssets/Interiors
112 MB 1 Documents/Scans
why: create-item → cannot synchronize (the server refused the operation)
3 of them have been GIVEN UP on (no further retries), last tried 21h25m ago
PENDING DELETES 2057 queued against the server
ERRORS
2 x FP -2005 cannot synchronize (the server refused the operation)
ARCHIVED 1 old sync folder(s) left behind by a domain re-registration, not scanned:
Nextcloud-cloud.example.com-you (01.01.26 12:00)
no live domain owns these - anything still in them exists nowhere else
A file waiting its turn in a large upload and a file the OS has abandoned look identical in a single reading: neither is on the server. Telling them apart takes a second reading — so give it somewhere to remember one, and it will:
$ ncstatus --state ~/.cache/ncstatus.json
Nextcloud SYNCING /Users/you/Library/CloudStorage/Nextcloud-cloud.example.com-you
███████░░░░░░░░░░░░░░░░░ 28.5% ↑ 6.10 GB / 21.40 GB 865 KB/s ~4h52m left
QUEUED 1284 files 15.30 GB waiting to upload - the queue is moving
And a few abandoned files is not the same as an abandoned sync. The two get separate verdicts, because a queue that is still draining does not need you right now — the files it has given up on will still be there when it finishes:
Nextcloud SYNCING - 12 STUCK /Users/you/Library/CloudStorage/Nextcloud-cloud.example.com-you
██████████████████████░░ 91.8% ↑ 19.64 GB / 21.40 GB 1.2 MB/s ~24m11s left
QUEUED 431 files 1.76 GB the queue is moving - but not all of it, see below
Five verdicts, and they mean different things:
UP TO DATE |
Nothing queued, nothing transferring. |
SYNCING |
The queue is being worked through. Percentage and ETA are measured over 15 minutes, not one tick. |
SYNCING - N STUCK |
The queue is moving, but it is leaving N files behind — abandoned, or refused by the server. Deal with them whenever; the rest is fine. |
STALLED |
There is a backlog and nothing has moved for ten minutes. Nobody will tell you this otherwise. |
STUCK |
Nothing left in the queue is still being retried (next: never). Nothing will finish without you. |
A file can be on the server and out of date. If you edit something that also changed on the server, the client will not guess which version wins — it just keeps trying and being refused. Nothing is missing, so nothing reports it missing; the folder looks complete and your edit exists on one disk only.
CHANGES NOT UPLOADED 1 file 60 KB the server has these files, but not your edits
60 KB Notes/ledger.xlsx
update-item → Upload rejected: the file changed on the server since it was last synced.
12 attempts, last 18m40s ago, next retry in 1h8min
the copy on the server is an older version - these changes are only here
ncstatus names the file, quotes the server's own reason, and tells you when it
will be tried again. What to do about it is a judgement call about your data, so
it stops there and leaves the decision to you.
There is also an optional menu-bar icon (SwiftBar) in the same five states — white when there is nothing to do, green while it works, amber when it works but is leaving files behind, red when nothing is moving at all. Click through to jump straight to the affected files in the Finder; abandoned ones are named first, so a handful of casualties is not buried under a thousand files that are simply waiting their turn.
It runs fileproviderctl dump and lstat()s. It never opens a file, because
opening a placeholder downloads it. It makes no network connections of its
own. The people most likely to run this are the ones whose sync is already
broken, and a diagnostic must not be able to make that worse.
It writes nothing at all unless you pass --state PATH, which keeps a small
list of past readings at a path you choose — the only way a one-shot run can know
whether the queue is moving. No config file, no implicit cache, nothing outside
that path.
It touches only Nextcloud folders. Google Drive and OneDrive are network filesystems where merely walking the tree is slow and can pull data down.
ncstatus-cleanup can move skipped files — the ones your client excludes
from sync by rule, so they will never upload — to the Trash. It is a different
executable for a reason: the value of a diagnostic is that you can trust it not
to touch anything, and a tool that sometimes deletes is not that tool. ncstatus
itself is unchanged and still writes nothing.
Even then it only ever moves what you tick in a list, it re-reads the file list at the moment you confirm rather than trusting the menu you clicked, it refuses anything that is not a plain file inside the sync root, and it uses the Trash — so a wrong selection costs a drag from the Trash, not a restore from backup.
The same tool can empty the client's leaked upload staging. Large uploads are cut into 100 MB chunks stored under the File Provider extension's container, and the client never deletes them — not even after a transfer that succeeded, and every retry leaves another copy (nextcloud/desktop#8995, open since November 2025). On the machine this was written on that had reached 134 GB, a third of the disk, entirely invisible from the client. ncstatus reports the size whenever it is over a gigabyte, and offers to clear it only when the sync is idle, nothing has been staged for ten minutes, and the client is closed. That one deletes outright rather than trashing — trashing 134 GB frees nothing until you empty it — which is why it names the exact directory and asks you to confirm.
Requires macOS and Python 3. No third-party packages.
git clone https://github.com/<you>/ncstatus.git
cd ncstatus
./ncstatusTo have it on your PATH:
ln -s "$PWD/ncstatus" /usr/local/bin/ncstatusncstatus # the report above
ncstatus --files # list individual stuck files, with real filenames
ncstatus --all # every affected folder, not just the top 12
ncstatus --watch 10 # refresh every 10s, with a live rate and ETA
ncstatus --state PATH # remember readings there: rate, ETA, moving vs stalled
ncstatus --json # machine-readable, for scripts and dashboards
ncstatus --scan # also tally materialized vs cloud-only on disk (SLOW)
ncstatus --list-domains # show registered File Provider domains
See MANUAL.md for what every line of the output means, the menu-bar setup, the JSON schema, and how it works internally.
MIT — see LICENSE.
Not affiliated with or endorsed by Nextcloud GmbH. "Nextcloud" and its logo are trademarks of their respective owner; the menu-bar icon depicts the mark solely to identify which sync client is being reported on.