pcloud-cli

๐Ÿ”„ Local sync inspection

Inspect the pCloud Drive sync daemon, diagnose broken sync pairs, and prune orphaned ones.

Every other command in pcloud talks to the pCloud API โ€” your files as the server sees them. This one reads the local database that the pCloud Drive desktop app keeps at ~/.pcloud/data.db, which is where sync pairs live.

That distinction matters because a sync pair can break in ways the API cannot see. The symptom you actually get is a dialog reading "pCloud doesn't have permissions to upload this item" against a folder shown as / โ€” which is neither a permissions problem nor a folder called /.

โž• Add a sync pair

pcloud sync add Memory          # dry run
pcloud sync add Memory --apply

Creates the remote folder and the local folder, then tells you the two paths to pair in pCloud Drive โ†’ Sync. It does the halves that are unambiguous and hands you the one that is not.

Why it does not create the pair itself

Because it was tried, and it fails in the worst available way.

Inserting a row into syncfolder directly โ€” with folderid, inode and deviceid all copied correctly from working pairs โ€” is accepted by the daemon. It watches the folder and indexes new files into localfile. But syncedfolder and localfolder stay at 0, where a working pair carries dozens each. The daemon ends up holding a file it knows about and no remote folder to put it in, so nothing uploads.

Worse, pcloud sync reports the pair healthy throughout: its checks look for an orphaned folderid, not for an index the daemon never built. A sync that will not start announces itself; this one reports fine indefinitely while moving nothing.

pCloud Drive builds that index when it creates a pair, so pairing is left to it.

What it does not do

A pCloud sync pair can bind any local folder to any remote folder โ€” the two need not share a name, and nothing requires them to sit under a common parent. add deliberately covers only the mirrored case, <root>/name โ†” /name, because that is the layout worth a shortcut. Pair anything else in pCloud Drive's preferences, then pcloud sync will report on it like any other.

Where the local folder goes

Four rungs, most specific first:

RungSource
--root <path>This run only
PCLOUD_SYNC_ROOTThis machine
Inferred from existing pairsThe parent every current pair shares
~/pCloudThe client's own conventional folder name

Inference abstains when existing pairs live under different parents โ€” a scattered layout is a legitimate way to use pCloud, not a fault, so it falls through to the default rather than picking a winner.

Guards

add refuses before creating anything, so a rejected run leaves no folders behind:

CheckWhy
Duplicate pairThe local folder is already synced
NestingpCloud syncs pairs independently โ€” an overlap uploads the same file twice
Root missingThe derived root does not exist on disk

Unlike prune and settings, add never opens data.db for writing, so it needs no backup, no daemon guard and no --yes. It reads the sync table to derive the root and check for conflicts, and writes only to the filesystem.

๐Ÿ“‹ Show sync pairs

pcloud sync
pCloud Drive   running
Database       ~/.pcloud/data.db ยท 3.13 MB

   Local                 Remote        Files   Queue
โœ“  ~/pCloud/Documents    /Documents    883     โ€“
โœ“  ~/pCloud/Photos       /Photos       172     โ€“
๐Ÿ”ฅ ~/pCloud/Archive      โ€” orphaned    2066    1
โœ“  ~/pCloud/Notes        /Notes        40      โ€“

๐Ÿ”ฅ #3  ~/pCloud/Archive
   no remote folder โ€” pCloud shows this pair as "/"
   a second sync pair claims the same local folder
   1 queued operation with no destination
   โ†’ pcloud sync prune 3

A stuck queue is a different fault from an orphaned pair, and takes a different remedy โ€” prune unpairs the folder entirely, which is right for a pair pointing at a deleted remote and wrong for a healthy one:

pcloud sync clear-tasks 3

Add an id for a single pair, or --json for machine-readable output:

pcloud sync 3
pcloud sync --json

๐Ÿ” What it checks

CheckMeaning
orphanedThe pair's remote folder is NULL โ€” nothing to sync into
remote-missingThe remote folder id is no longer in the local index
duplicateTwo pairs claim the same local folder
local-missingThe local folder no longer exists on disk
stuckQueued operations with no destination folder to act on

orphaned is the interesting one. syncfolder.folderid is declared ON DELETE SET NULL, so when a remote folder is deleted, SQLite blanks the reference instead of removing the sync pair. The pair survives as a zombie pointing at nothing, and every upload it attempts fails.

๐Ÿงน Prune an orphaned pair

pcloud sync prune 3          # dry run โ€” shows what would be deleted
pcloud sync prune 3 --apply  # perform it

The dry run is the default. --apply backs up data.db first, and refuses to run while pCloud Drive is open โ€” the daemon holds its own copy of the sync set in memory and would either overwrite the edit or corrupt the write-ahead log. Quit pCloud Drive, apply, then start it again.

Pruning removes only the local index rows for that pair. It touches no files, on disk or in the cloud.

๐Ÿ”ฌ Debug view

pcloud sync --debug

Shows daemon state, database size, write-ahead-log status, and row counts per table.

On privacy: the same database holds setting, cryptofilekey and cryptofolderkey โ€” your auth token and crypto key material. The debug view works from an allowlist of tables it may read, never an exclusion list, so a table pCloud adds in a future release is withheld by default rather than leaked. Withheld tables are named, never read.

๐Ÿฉบ In doctor

pcloud doctor runs these checks as a second section after its credential report, and prints a one-line verdict per fault class:

Local daemon
  7 sync pair(s) ยท pCloud Drive running
โœ“ no local sync faults

The local half needs no credential, so it still runs when you are logged out.

๐Ÿ”’ Read-only, and lock-safe

pCloud Drive holds the database under an exclusive lock while it runs, so pcloud sync copies the database and its write-ahead log to a temporary directory and reads the copy. Your live database is only ever copied, never opened by SQLite โ€” prune --apply is the sole exception, and it requires the daemon to be stopped.

On this page