[Android] A single uncreatable file (filename > 255 bytes) fails the startup scan, which silently gates all replication behind "Not ready"

Author: robgcrockettCreated Sep 4, 2026Updated Sep 6, 2026
Labelsawaiting confirmation

Summary

On Android, one document whose filename exceeds the filesystem's 255-byte limit causes the startup full scan to report 1 failed. Because prepareDatabaseForUse only calls appLifecycle.markIsReady() when vault.scanVault() returns true, and the scanner returns failedCount === 0, the plug-in never reaches the ready state. Every replication path (Sync now, Sync with a saved connection, LiveSync mode) is then refused with only the two-word log line [ReplicationService] Not ready, and no notice is shown. The device stops syncing in both directions.

The same vault syncs correctly on Windows, where the 255 limit is counted in characters rather than bytes, so the file is created without error and the scan passes.

A second, smaller issue surfaced while working around the first: the "Non-Synchronising files" regex list strips all spaces before compiling, so a pattern containing spaces can never match.

Environment

  • Self-hosted LiveSync 1.0.24 (@vrtmrz/livesync-commonlib 0.1.21)
  • Android 17, Pixel 11 Pro XL, WebView Chrome/152
  • Obsidian mobile (current)
  • Remote: self-hosted CouchDB, remoteConfigurations.legacy-couchdb active, E2EE off
  • Desktop: Windows 11, same plug-in version — syncs normally

Steps to reproduce

  1. On a desktop client, create a note whose filename is ≤ 255 characters but > 255 bytes in UTF-8 (e.g. ~250 characters including a few curly quotes “ ”, which are 3 bytes each). Windows/NTFS accepts it.
  2. Let it replicate to CouchDB and then to an Android client.
  3. Restart Obsidian on Android and open the LiveSync log.

Actual behaviour

Log on Android (verbose):

[ServiceFileHandler]  File Work/<folder>/<261-byte name>.md   (forced)
Error processing Work/<folder>/<261-byte name>.md with action update-storage
Error:FILE_NOTCREATED
[StackTrace]: _LiveSyncError: [Error Logged]: FILE_NOTCREATED
    at processFilePair (plugin:obsidian-livesync:6:386401)
[CausedBy]: Error
    at win.androidBridge.onmessage (http://localhost/:890:21)
[SF:OfflineScanner]  Synchronisation completed: 8401 files processed (4183 completed, 4217 skipped, 1 failed)
[SF:OfflineScanner]  Initialized, NOW TRACKING!

Then, on Sync now, Switch active connection, or Sync with a saved connection:

Switched to remote: CouchDB Remote (Active)
[ReplicatorService]  Active replicator has been kept
[ReplicationService]  Not ready

Status bar shows Sync: ■ ↑0 ↓0. No notice or dialogue is shown. The compatibility review had already been completed (the Review why synchronisation is paused command is not offered). Nothing replicates in either direction until the failing document is excluded.

Expected behaviour

One file that cannot be materialised on this platform should be reported (ideally with a persistent notice naming the file) and skipped, and replication should continue for the other 8,400 files. At minimum, the readiness gate should say why it is not ready rather than the bare Not ready.

Root cause (from reading 0.1.21 dist)

  • services/base/ReplicationService.readiness.ts — the application-ready condition logs "Not ready" and returns false when appLifecycleService.isReady() is false. This is the only diagnostic emitted.
  • serviceFeatures/prepareDatabaseForUse.ts — calls appLifecycle.resetIsReady() first, then returns false (without logging) if vault.scanVault() returns false, so markIsReady() is never reached.
  • serviceFeatures/offlineScanner.tssynchroniseAllFilesBetweenDBandStorage returns failedCount === 0; performFullScan returns that result unchanged as the scanVault handler's result.

So one FAILED pair from processFilePair → scan returns false → app never marked ready → all replication gated, silently.

There is also a chicken-and-egg consequence: the failing document lives in the local database, so renaming it on another device cannot help — the Android client cannot receive the rename until it replicates, and it cannot replicate until the scan passes.

Suggested fixes

  1. Treat per-file FILE_NOTCREATED (and similar platform-storage failures) as non-fatal for readiness: report and skip the pair, or raise an unresolved-error notice naming the path, but still mark the app ready so replication proceeds.
  2. Have prepareDatabaseForUse log which step failed (openDatabase, isDatabaseReady, scanVault, onDatabaseInitialised, commitPendingFileEvents) when it returns false, and have the readiness evaluator surface that reason instead of Not ready.
  3. Optionally, warn when a document's path exceeds 255 bytes in UTF-8, since that is the effective limit on Android/Linux and iOS, while Windows counts UTF-16 characters.

Second issue: "Non-Synchronising files" regex list strips spaces

common/utils.tsparseCustomRegExpList:

javascript
const items = source.replace(/\n| /g, "").split(d).filter((e) => e);

Every space in the stored pattern list is removed before new RegExp(...). A pattern such as Brook and the Stauffers is compiled as BrookandtheStauffers and never matches; the UI (PaneSelector.tsMultipleRegExpControl) accepts it without warning. Brook.and.the.Stauffers works. Suggest either not stripping spaces (splitting only on the |[]| delimiter) or rejecting/escaping spaces in the control with a hint.

Workaround that resolved it

  1. General Settings → Extra menus → Enable advanced features (the Selector pane is otherwise hidden).
  2. Selector → Non-Synchronising files → add a space-free pattern matching the offending filename.
  3. Force-close and reopen Obsidian. Scan completes with 0 failed, markIsReady() is reached, replication starts, and the client pulls the rename made on the desktop.
  4. Remove the pattern afterwards.

Relationship to #1148

The symptom (Not ready on Android, desktop fine) looks like #1148, but that report shows [ReplicatorService] No remote replicator configuration found and InitialiseFatalError at startup. Neither appears here; the active configuration is present and the failure is entirely the scan-result gate. Filing separately, but linking in case the readiness diagnostics fix covers both.

Full debug report available on request (CouchDB URI and credentials redacted).

Source: vrtmrz/obsidian-livesync