Skip to content

Unable to backup directories containing control characters #228

Description

@svandragt

jotta-cli release (jotta-cli version):

0.17.176206 (stable, from repo.jotta.cloud/debian; apt-cache policy jotta-cli shows the installed version and the candidate are identical, so this is the latest.)

Description of problem:

A directory whose name contains a newline (0x0A) cannot be backed up, and deleting it locally leaves jottad retrying a remote delete of it on every scan, permanently, with no way to clear the entry from the client.

The directory was pkQtSp0i.Profile 1\npkQtSp0i.Profile 1 under ~/.config/mozilla/firefox/, inside the /home/user backup root. A script of mine created it by passing an unquoted, newline-separated list to mkdir -p, so the name holds a literal newline. It is legal on Linux and ls shows it as two lines.

It went through three stages.

  1. While the directory existed, every backup scan tried to create it remotely and the server rejected the name:

    error mkdir /backup/<uuid>/user/.config/mozilla/firefox/pkQtSp0i.Profile 1
    pkQtSp0i.Profile 1/chrome: xid: cmZsUkdZQ0ZFYXVP message: invalid argument code: 12 type: INVALID_ARGUMENT
    

    Nothing else was affected and no error surfaced in jotta-cli status, so the subtree was simply never backed up. The directory dated from March.

  2. I deleted the directory, which made it worse. jottad now tries to delete the corresponding remote folder, the server rejects the same name, and jottad marks the entry dirty and tries again on the next scan:

    Deleting remote folder: /backup/<uuid>/user/.config/mozilla/firefox/pkQtSp0i.Profile 1
    Error deleting /backup/<uuid>/user/.config/mozilla/firefox/pkQtSp0i.Profile 1
    pkQtSp0i.Profile 1: rpc error: code = InvalidArgument desc = {"message":"invalid argument","xid":"amlXYU94eFRSYUhM","encodedError":null,"errors":[{"type":"INVALID_ARGUMENT","code":12}]}
    No data for folder??? /home/user/.config/mozilla/firefox/pkQtSp0i.Profile 1
    pkQtSp0i.Profile 1/chrome
    marked /home/user/.config/mozilla/firefox/pkQtSp0i.Profile 1
    pkQtSp0i.Profile 1 as dirty
    

    It has repeated on every scan since, across daemon restarts, for about 12 hours.

  3. The remote folder never existed, because the mkdir in stage 1 never succeeded. jotta-cli ls Backup/<device>/user/.config/mozilla/firefox lists only the valid sibling pkQtSp0i.Profile 1, and jotta-cli dump shows the row driving the deletes with no files in it:

    {"backuproot":"/home/user","folder":"/.config/mozilla/firefox/pkQtSp0i.Profile 1\npkQtSp0i.Profile 1","files":[]}

    So jottad is asking the server to delete a folder that cannot exist, and cannot learn that it does not exist, because the request is rejected on the name before any lookup happens.

There is no way out of this from the client. I tried:

  • restarting jottad — the row is in the local database and survives into the new pid;
  • jotta-cli ignores add for the path — this makes it worse, because a newly ignored path is treated as "remove from the remote", which triggers the same rejected delete. I used jotta-cli ignores test first to confirm the pattern could not also match the valid sibling;
  • recreating the directory and renaming it — a rename still has to delete the old name remotely, which is the rejected call;
  • deleting it through the web interface — there is nothing there to delete;
  • emptying the trash, which is irrelevant here since **Trash/** is already ignored.

One observation that may point at the fix. In #117 you write that jottad should ignore invalid or unprintable ASCII characters when scanning. That does appear to work for files: a Icon\r file elsewhere in the same tree logs scanner.filtered ... and is skipped cleanly, with no error and no retry. Directory names do not get the same treatment — they are attempted, and fail.

Expected:

  1. A directory whose name the API cannot represent should be skipped during scanning, the way such files already are, and logged once rather than retried on every scan.
  2. Failing that, a delete rejected as INVALID_ARGUMENT for a path that cannot exist server-side should not be retried indefinitely. Dropping the local row would be better than looping on it for ever.
  3. jotta-cli ignores add would be a reasonable escape hatch for an entry already in this state, but at present it causes the failing delete rather than avoiding it.

jotta-cli status (jotta-cli status):

------------------------------------------------------------------------------
 Account   : <redacted> on Jottacloud
 Usage     : <redacted> / ( Unlimited )
 Device    : <device>
------------------------------------------------------------------------------
 Sync      :
------------------------------------------------------------------------------
   Path      : /home/user/me/sync
   Files     : 144821 (61.75GiB)
   Mode      : listening to events
   Status    : Up to date - 2026-08-18 11:16:24
------------------------------------------------------------------------------
------------------------------------------------------------------------------
   Path      : /home/user
   Files     : 1060427 (200.87GiB)
   Status    : 6 file(s) (2.66MiB) have not been backed up

------------------------------------------------------------------------------

Note that the status output says nothing about this. That is the practical problem: the only sign is in the log.

Relevant logs for the issue (~/.jottad/jottabackup.log)

pid:1790142 2026/08/18 11:16:02 Deleting remote folder: /backup/<uuid>/user/.config/mozilla/firefox/pkQtSp0i.Profile 1
pkQtSp0i.Profile 1
pid:1790142 2026/08/18 11:16:02 Error deleting /backup/<uuid>/user/.config/mozilla/firefox/pkQtSp0i.Profile 1
pkQtSp0i.Profile 1: rpc error: code = InvalidArgument desc = {"message":"invalid argument","xid":"amlXYU94eFRSYUhM","encodedError":null,"errors":[{"type":"INVALID_ARGUMENT","code":12}]}
pid:1790142 2026/08/18 11:16:02 No data for folder??? /home/user/.config/mozilla/firefox/pkQtSp0i.Profile 1
pkQtSp0i.Profile 1/chrome

Earlier, while the directory still existed locally:

pid:2575 2026/08/17 07:21:19 error mkdir /backup/<uuid>/user/.config/mozilla/firefox/pkQtSp0i.Profile 1
pkQtSp0i.Profile 1
pkQtSp0i.Profile 1/chrome: xid: cmZsUkdZQ0ZFYXVP message: invalid argument code: 12 type: INVALID_ARGUMENT

Each of these is one log message containing a newline, which is why they render as two or three lines.

Traceback

None. Nothing panics; the scan completes normally and reports success.

Additional info:

Platform: elementary OS 8, kernel 7.0.0-28-generic, x86_64.

To reproduce, inside a backup root:

mkdir -p "$(printf 'one\ntwo')"

Wait for a scan and the mkdir failure appears. Remove the directory and the delete failure begins, and then repeats on every scan.

To find such names on a machine:

find "$HOME" -print0 | LC_ALL=C grep -zaP '[\x01-\x1f]' | tr '\0' '\n'

Possibly related, though I think distinct: #117 covers invalid UTF-8 bytes in file names failing at the checksum step, and #90 asks for better handling of unusual file names generally. This one is a control character in a directory name, rejected by the API, ending in a retry loop that cannot be cleared.

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