Docs / Using the app / Troubleshooting
Troubleshooting
What to do when sync pauses, a note looks unsaved, search finds nothing, an installer is blocked, or you need to restore something you deleted.
Most Jotura problems fall into a handful of categories, and almost all of them have a specific message attached. This page is organized by what you are looking at. Where a fix needs the command line, the exact command is given.
One thing to rule out first. Nothing in Jotura blocks local work. Reading, writing, and keyword search never wait on sync, on a key, or on the network. If the editor itself is unresponsive, that is a different problem from any of the sync states below.
Start with the built-in checks
The jotura doctor command runs a sequence of checks over the vault, sync state, shares, documents, semantic search, and the bundled document converter, then prints the results.
jotura doctor
Add --json when a script needs to read the result:
jotura doctor --json
Doctor emits an array of { name, status, detail } objects, where status is one of pass, warn, fail, or info. The checks are emitted in this order:
| Check | What it tells you |
|---|---|
cli-on-path | The current executable path, and whether its directory is on $PATH. |
cli-version | The version of the CLI binary you just ran. |
vault-detected | The resolved vault path, or advice to set $JOTURA_VAULT. |
vault-readable | Whether the vault directory lists cleanly. |
sync-enabled | Whether the vault has sync configured, plus active or paused and the pending op count. |
sync-key-cached | Only emitted when sync is enabled. Advises jotura sync login when the key is missing. |
shares-registry | Whether the share registry parses, and how many entries it holds. |
share-mount | One per share. Whether the registry’s mount folder exists on disk. |
share-sync-db | One per share. Sync database existence and pending op count. |
share-key-cached | One per share. Whether that share’s key is cached on this device. |
documents | Converted, failed, pending, and total document counts. |
documents-failed | Up to 10 failing document paths, emitted as one check each. |
documents-failed-note | Points you at regenerate-md-store --stale-only. |
semantic-index | Missing, disabled, unopenable, or enabled with chunk and pending counts. |
semantic-model | The model directory path, or that the files are missing. |
semantic-runtime | Whether the embedding runtime loads, and which backend it picked. |
desktop-app-version | The appVersion recorded in the desktop app’s settings.json. |
markitdown-sidecar | The document converter’s version, or that it was not found next to the CLI. |
markitdown-sandbox | Whether a usable operating system sandbox is available for document conversion. |
diagnostics-log | The path to the local diagnostics log. |
diagnostics-recent | The five most recent log lines, emitted as one check each. |
The array is longer than that list of names, because share-* repeats per share, documents-failed repeats per failing document, and diagnostics-recent always contributes five entries.
Doctor will trip up a script in a way worth knowing in advance. It always exits 0, even when a check has status fail, so you cannot use its exit code as a health gate and must parse the JSON instead. It is also deliberately vault-tolerant: it resolves the vault itself and reports a missing vault as a failed check rather than exiting with an error.
Five checks can report fail: vault-detected, vault-readable, sync-enabled, share-mount, and markitdown-sandbox. Every semantic check is informational at worst, because keyword search keeps working whatever the embedding index is doing.
The second diagnostic lives in the app. Open Settings, expand Advanced, then Diagnostics. Copy diagnostics puts a support bundle on your clipboard, and Log file shows the path to the local log. Nothing is sent anywhere. You paste the bundle into a bug report yourself.
My note did not save
Jotura has no Cmd+S or Ctrl+S. Saving is automatic and there is no manual save command anywhere in the app, so pressing the chord does nothing and shows nothing.
What actually happens is this. The editor writes to disk one second after your last change. It also flushes immediately when the editor loses focus and when the window becomes hidden, so switching apps or closing the window saves your work without waiting out the timer. Every save goes through a serial queue, so an autosave timer and a blur flush can never conflict with each other.
The visible signals are worth learning, because they are quiet. A tab with unsaved changes shows a single • after its title, and the app announces Saved to screen readers when the write lands. Read-only tabs never become dirty and never autosave.
The one way to genuinely lose an edit is to force-quit the app within a second of typing, before the timer fires and without the window losing focus first. Clicking outside the editor, or switching to another application, closes that window.
Sync says it is paused
Sync has several distinct paused states and they need different fixes. The footer pill and the banner above the tab bar both name the state, and Settings then Account & sync shows the full status row.
| What you see | What it means | What to do |
|---|---|---|
Sync paused. Enter your sync password. | The vault is sync-enabled but this device has no cached key. | Click Unlock on the banner, click the Sync paused pill in the footer, or open Settings and use the Unlock sync… button in the Sync password needed row. |
Sync paused. You're signed out. | There is no account session on this device. | Click Sign in on the banner or the footer pill, then complete the email code flow. |
Paused. Server copy preserved. Resume to push pending edits. | Sync was paused deliberately. | Open Settings and click Resume sync. |
Subscription needed | The account has no active Sync subscription. | Sync is the one paid part of Jotura. See pricing. |
Offline. Will retry when online. | The device reports no network. | Nothing. Sync resumes when the connection returns. |
Error: <message> | A push or pull failed. | Read the message, then work through the sync diagnostics rows in Settings. |
The banner text itself is not a click target. Each banner carries two buttons, the action (Unlock or Sign in) and Dismiss, and dismissal is remembered per vault. In the footer pill, only the Sync paused and Sign in states are buttons; the rest are plain status text.
The missing-key case is the common one, and it is not a failure. Your notes stay fully readable and editable while sync is paused, and edits queue locally and push once the key is back.
You can supply the key from either surface. In the app, enter your sync password in the unlock modal, or use the 12-word recovery phrase if you have lost the password. From the terminal:
jotura sync login
That prompts for the password with no echo and caches the key. To unlock with the recovery phrase instead:
jotura sync login --recovery-phrase
To feed the secret from a script rather than a prompt:
jotura sync login --passphrase-stdin
A wrong password or an invalid recovery phrase both exit 9 (InvalidArgs) rather than a dedicated authentication code.
The desktop app and the CLI share one per-vault key cache under <config>/jotura/sessions/, so unlocking in either surface resumes the other. On Unix the cache files are mode 0600 inside a 0700 directory. On Windows they rely on the user profile ACL.
Check the state at any time:
jotura sync status
That reports enabled, keyCached, paused, pendingOps, and a per-share array. It never errors on a vault without sync, it simply reports enabled: false. By contrast, jotura sync login, jotura sync logout, and jotura sync drop-path exit 12 (SyncNotEnabled) on a vault that has no sync configured.
Enabling sync, setting or changing the sync password, and restoring a vault from the cloud are all desktop-only operations. The CLI manages the local key cache and reports state, nothing more.
If you deliberately cleared the key with Forget key on this device in Settings under Security & recovery, this is exactly the expected result. That action clears the in-memory keys and deletes the session cache, so sync moves to the needs-key state while local editing carries on untouched.
More on how sync behaves: Sync and sharing and Sync and shares from the CLI.
Changes from another device are not appearing
Sync is a 5 second poll rather than a live push, so a short delay is normal. When a change is genuinely stuck, the app has a dedicated repair.
Open Settings, go to Account & sync, and find Re-pull from server among the sync diagnostics rows. It resets the local sync cursor to zero and re-fetches the entire manifest. It confirms first with Re-fetch the entire manifest from the server? Local pending edits are kept.
Its helper text warns that any diverged file becomes a .conflict-* sibling. In practice, sync itself never creates conflict files: the pull path 3-way merges divergence into the canonical file, and the machinery that would write a .conflict- sibling is not reachable from any control in the current app. Treat the warning as belt-and-braces rather than as something you should expect to see.
The diagnostics rows above that button are the useful reading while you are here: Account, Device ID, Vault ID, Pending ops, Server version, Last push, Last pull, Last push error, and Last pull error. A non-empty error row is the fastest answer to why nothing is moving.
One repair lives only in the CLI. If a path is tracked in sync under a stale or case-aliased string, for example a daily-notes folder that once synced as daily and now lives at Daily, drop the stale string from tracking:
jotura sync drop-path "daily/2026-08-29.md"
It matches the synced-paths table by exact string, not by looking at the filesystem, and it never touches local files. It exits 3 (NotFound) when no synced row matches, and 9 (InvalidArgs) for an empty path or anything under .jotura/. The deletion propagates to your other devices on the app’s next sync.
Never fix a case-aliasing problem by deleting the file instead. A file delete propagates as a real deletion to every device, and you lose the note.
A share is misbehaving
Shared folders have their own failure modes, and one of them can destroy other people’s copies if you ignore it.
A share-mount check reporting fail means the share registry points at a folder that no longer exists on disk. Left alone, that stale entry can propagate a share-wide deletion the next time the desktop app launches, which affects everyone in the share and not just you. Fix it in the desktop app by re-mounting the share, or by leaving the share outright. The same condition shows up in the CLI as MISSING in the MOUNTED column:
jotura shares list
A shares-registry check reporting warn means the registry file does not parse. Reads treat a broken registry as empty, so your shares vanish from listings, while writes are refused until it is repaired. Shares disappearing from the sidebar at the same moment that edits start failing is this one problem, not two.
Status dots in the Shared pane carry their explanation in the tooltip. The exact strings are Not syncing yet, Up to date, Syncing…, Needs your sync key, Your role changed. Edits here can't be saved, Subscription needed to keep this share syncing, Sync error: {message}, Offline, will retry, Paused, and Not syncing.
Writes into a share you can only view are refused rather than queued. From the CLI that is exit 15 (ReadOnlyShare), and the error JSON carries path, shareId, and mountRel. There is deliberately no override flag, because a forced viewer write would never sync and would be overwritten by the next remote change. Ask the owner for editor access.
On mobile, a 403 from the server after a role change is a role block, not a teardown. The share is still yours; you have simply lost write access to it.
Share management itself, meaning inviting, promoting, removing members, and leaving, is desktop-only. A machine with only the CLI installed also cannot receive a new share, because mounting happens when the desktop or mobile app runs discovery. Once a share is mounted, the CLI is fully aware of it.
Search finds nothing
Most reports of broken search turn out to be one of four surfaces behaving exactly as designed but not as expected.
| Surface | How you open it | What it actually searches |
|---|---|---|
| Sidebar search pane | The Search icon in the sidebar, or the Dashboard’s Search vault tile | Keyword only, over titles and content, with separate Titles (N) and Content (N) result groups |
| Search page | Cmd/Ctrl+Shift+F, or the Open Search Panel command | Keyword, Semantic, or Smart, whichever mode is selected |
| Quick open | Cmd/Ctrl+P | The file base name only. Not the path, not the note content |
| Source mode | Cmd/Ctrl+Shift+E inside a note | Nothing. There is no in-pane find |
Three consequences are worth spelling out.
Quick open matching only the base name is the single most common surprise. Searching it for a phrase you know is inside a note returns nothing, and there is no > prefix for commands and no #tag filter to fall back on. Use the search page for content.
The Dashboard’s Search vault tile opens the sidebar pane, while the identically named Open Search Panel command also opens the pane and Cmd/Ctrl+Shift+F opens the separate search page. Same words, two different destinations.
Source mode installs only CodeMirror’s default and history keymaps, so Ctrl+F does nothing there. Toggle back to the editor and use the search page instead.
If body results look incomplete right after opening a vault, check the sidebar for the strip reading Indexing… {done}/{total}. Content results are partial until that clears. Full detail on all of this is on the Search page.
From the terminal, be aware that jotura search builds an in-memory index over the whole vault on every invocation. That is fine for thousands of notes on a single query, but do not put it in a loop.
jotura search "quarterly review"
Semantic and Smart search are greyed out
The search page offers three modes, Keyword, Semantic, and Smart. Semantic and Smart stay disabled until the local embedding model is ready, with the tooltip Enable semantic search to use this mode. Because the stored default mode is smart, the page silently falls back to keyword rather than failing when the model is absent, which is why the greyed-out buttons are often the only clue.
To enable it, open Settings and find the Semantic search section. Turning it on downloads two files, model.onnx and tokenizer.json, roughly 34 MB in total, from https://releases.jotura.io/models/bge-small-en-v1.5-int8/v1/ into <config>/jotura/models/bge-small-en-v1.5-int8/v1/. Both are SHA-256 verified. The section then shows the model version, the runtime backend (one of GPU (CUDA), GPU (DirectML), GPU (CoreML), CPU, or Unknown), and an index row reading <n> chunks · <n> pending with an estimated time while embedding runs.
The model and the index stay on your device. Nothing is sent anywhere.
Re-index vault, in the same section, wipes the chunks and rebuilds them in the background. Turn off & delete index below it is destructive: it deletes the vector database along with its -wal and -shm sidecars. Your notes are untouched, and re-enabling rebuilds the index.
From the CLI, semantic and smart search exit 13 (SemanticUnavailable) when the prerequisites are not met:
jotura search "how did we decide on the queue design" --mode semantic
The error message names the specific missing prerequisite. The possibilities are that <vault>/.jotura/vectors.db does not exist, that the database’s enabled flag is not set, that no config directory can be resolved, that the embedding model files are absent from the path above, or that the ONNX runtime cannot be resolved or fails to load.
Stale or missing results from the terminal are usually a limit rather than a bug. The CLI is query-only: it embeds your query but never indexes notes, so freshness equals the desktop app’s last indexing pass and a note you just wrote from the terminal is not semantically searchable until the app reindexes it. And --in does not work with semantic modes: combining it with --mode semantic or --mode smart exits 9 (InvalidArgs), because path scoping is keyword-only.
Images in my notes are blank
Web images do not load by default. The Load remote images setting under Settings then Editor is off, because fetching a web image tells its host your IP address and the fact that you are reading that note. Turn it on if you trust the sources in your vault.
Images stored inside the vault are unaffected by that setting and always render.
Separately, an .html note that “does not work” is usually behaving as designed. Jotura renders HTML files inside a fully sandboxed frame with scripts disabled, so anything interactive in the file is inert on purpose.
“Vault not found” after signing in
This error comes from the server, and it almost always means the app is pointed at a different API environment than the one the vault was registered against. A vault registered on one environment does not exist on the other.
Installed release builds default to https://api.jotura.io and need no configuration. Two things can move them off it.
The JOTURA_API_URL environment variable overrides the default at resolution time. It is never persisted, so unsetting it and restarting restores the default. The apiBaseUrl field in settings.json also carries the value, and it has no control in the Settings UI. A settings file still holding the old staging URL is migrated to the production URL automatically on load.
If you have set JOTURA_API_URL for testing, clear it and restart before investigating anything else. If you genuinely work across two environments, use a separate scratch vault for each rather than repointing one vault.
The installer is blocked on first launch
Jotura’s macOS builds are ad-hoc signed rather than signed with a paid Apple Developer identity, so Gatekeeper refuses the first launch. Signed and notarized distribution is a known gap, not an oversight.
Running the app straight from the mounted disk image fails in a confusing way rather than an obvious one: file dialogs and configuration writes are blocked, so the window may never appear, or may appear empty. The reliable sequence is:
- Open the
.dmgand drag Jotura into your Applications folder, replacing any earlier version. - Strip the quarantine attribute from the copy you just made.
- Eject the disk image.
- Launch Jotura from Applications.
Step 2 is this command:
xattr -cr /Applications/Jotura.app
If Gatekeeper still refuses, right-click the app in Applications and choose Open, which offers a confirmation the plain double-click does not. Subsequent launches work normally either way.
To check which version actually installed, compare the app’s own About section in Settings, which reads Version <n>, against the bundle on disk:
defaults read /Applications/Jotura.app/Contents/Info.plist CFBundleShortVersionString
Windows has the equivalent problem for the same reason. The installer is unsigned, so SmartScreen warns that it comes from an unrecognized publisher and you have to choose to run it anyway. A Windows code-signing certificate is deferred alongside the Apple one.
The jotura command is not found
The CLI ships inside every desktop installer, but how it reaches your PATH differs per platform.
| Platform | Where the CLI lands | How it gets on PATH |
|---|---|---|
| macOS app bundle | Jotura.app/Contents/MacOS/jotura | Open Settings, expand Advanced, then Command-line tool, and click Install. This symlinks /usr/local/bin/jotura and prompts once for an administrator password. |
| Windows MSI | The install directory | The MSI adds that directory to the system PATH during installation. Open a new terminal afterwards, since existing ones keep the old environment. |
Linux .deb | /usr/bin/jotura | Automatic. No action needed. |
| Linux AppImage | Inside the AppImage | First launch offers to copy the binary to ~/.local/bin/jotura. That directory must already be on your PATH for the command to resolve. |
The Command-line tool card only appears when the running build actually bundles a CLI, so it is absent from builds installed another way.
The startup install prompt, which appears on Windows and the Linux AppImage only, records that it asked regardless of whether you said yes or no. It never asks a second time and there is no way to reset it from Settings, so install from the Settings card instead if you dismissed it.
The other sharp edge is a Windows failure message, Could not update PATH. That comes from the in-app Command-line tool card, which is a different mechanism from the MSI’s. The card writes the user PATH through PowerShell ([Environment]::SetEnvironmentVariable) rather than setx, because setx truncates PATH beyond 1024 characters, and then broadcasts a settings-changed message so new processes pick it up. If you see that message, the MSI’s system PATH entry is not the thing that failed.
To remove the macOS symlink later:
sudo rm /usr/local/bin/jotura
To confirm what the shell is actually resolving, and whether its directory is on PATH:
jotura doctor
The cli-on-path check prints the current executable path and whether its directory is on $PATH. Version skew is worth ruling out at the same time:
jotura --version
An installed CLI can lag the desktop app by a full release. That is not just a missing flag here and there: a whole command group can be absent from the older binary, and commands that do exist can emit different fields. Compare that output against the About section in Settings, and reinstall from the Command-line tool card if they disagree. Setup detail lives on Install and setup.
Edits from another device or another app
Jotura does not ask you to resolve content conflicts. This is deliberate, and it is worth understanding so the behavior does not look like a bug.
When a note open in the editor changes on disk, the app performs a silent three-way merge rather than prompting. The base is the tab’s last clean content, yours is the editor content, and theirs is the fresh copy from disk. It retries up to three times and announces Merged changes from disk when it succeeds. Sync pulls use the same merge, and neither path writes conflict markers into your text.
The merge is generous with genuinely different additions and decisive about near-identical ones, which is the part that surprises people. Two lines that share at least 80 percent of their bytes are treated as two edits of the same underlying line, a checkbox toggle or a fixed typo, and collapse to a single variant: the remote edit when your copy is unchanged from the base, and your edit when both sides changed it. So rewording the same sentence on two devices does discard one version. Lines that differ more than that, for example - buy milk against - buy eggs, both survive, and you end up with the two versions sitting next to each other rather than one of them disappearing.
Content that cannot be merged as text keeps the local bytes. That covers binary files, non-UTF-8 content, a delete racing a dirty edit, and a shape mismatch between the two sides. For file writes the sync row and base advance, so replaying the same operation is a no-op rather than a fresh conflict on every pull.
There is exactly one conflict prompt in the app: the banner reading This note was deleted or moved outside the app. with Close tab and Recreate with my version. That last option re-reads the disk hash and writes your version unconditionally. Full history and restore options are covered in Version history.
From the CLI, conflicts surface as exit codes rather than prompts. Exit 2 (HashConflict) means the --if-hash precondition did not match, and the error JSON carries a currentVsIntended unified diff. Exit 14 (TargetMissing) means the file was deleted or moved between your read and your write, and Jotura deliberately does not recreate it. The safe loop is always read, transform, then write with the hash:
HASH=$(jotura read notes/today.md --json | jq -r .hash)
jotura edit notes/today.md --replace "old" --with "new" --if-hash "$HASH"
Both the CLI and the desktop app serialize on a per-vault advisory lock held across the hash compare and the write, so two writers validating the same hash can never both succeed. The loser gets exit 2. See Editing notes.
Restoring something you deleted
Jotura’s Move to trash does not use the operating system trash. It moves the entry into <vault>/.jotura/trash/ alongside a .trashmeta sidecar recording the original path, size, and time, then announces Moved "<name>" to trash.
There is no trash browser in the desktop app. Listing, restoring, and permanently deleting trashed items are CLI-only today. This is a real gap, not a hidden menu.
jotura trash list
That prints the original path and the time it was trashed, one per line, or a JSON array with --json. Restore by the item’s original path, not the path inside the trash directory:
jotura trash restore "notes/quarterly review.md"
To restore somewhere else instead:
jotura trash restore "notes/quarterly review.md" --rename-to "archive/quarterly review.md"
The share guard applies to the destination, so restoring into a share where your role is viewer exits 15 (ReadOnlyShare).
The remaining trash commands are permanent:
| Command | Effect | Notes |
|---|---|---|
jotura trash <path> | Soft-delete a note. | Same as the app’s Move to trash. Refuses a share mount root. |
jotura trash purge <path> | Permanently delete one trashed item. | Takes the original path. No confirmation flag, and unlike the other three it does not route through the share guards. Whether that omission is intentional is unconfirmed. |
jotura trash empty --force | Permanently delete everything in the trash. | --force is required. Without it the command exits 9. |
Note the asymmetry: trash empty demands --force and trash purge does not. Also note that jotura delete <path> is permanent by default and only soft-deletes when you pass --trash. Deleting a path that does not exist is a silent success on a real run, though --dry-run reads first and exits 3. Lifecycle detail is on Creating, moving, and deleting.
Settings appear to have reset themselves
Settings live in a single JSON file:
| Platform | Path |
|---|---|
| Windows | %APPDATA%\jotura\settings.json |
| macOS | ~/Library/Application Support/jotura/settings.json |
| Linux | ~/.config/jotura/settings.json |
Two behaviors can look like a reset. The file is written with a plain write rather than a write-then-rename, so a crash during the write can truncate it. When the file fails to parse, Jotura falls back to built-in defaults silently rather than refusing to start. The combination means a bad shutdown can present as every preference reverting at once.
Separately, the Settings UI updates optimistically and does not surface a failed write back to disk. If a setting keeps reverting on restart while looking correct in the app, that is the shape of the problem, and the diagnostics log is the place to look.
Adding a setting is backward compatible: missing fields fall back individually rather than resetting the whole file. The full list of controls is on the Settings reference.
Imported documents failed to convert
Imported documents (PDF, Word, spreadsheets, and similar) are converted to searchable markdown by a bundled converter. Open Settings, expand Advanced, then Document conversion to see the state. The badge reads Unavailable when the converter is missing entirely, otherwise <n> failed.
Four actions sit in that section: Reconvert stale documents, Reconvert all documents, Convert pending documents, and Retry failed conversions. The helper text under the last one is honest about the usual cause: failures are usually corrupt or password-protected files.
From the CLI, retry only the entries that are actually out of date:
jotura regenerate-md-store --stale-only
Each result carries a reason of Missing, SourceChanged, ConverterUpgraded, or PreviousFailure. Be aware that --stale-only and --all take precedence over any explicit paths you also pass, and those paths are silently ignored rather than warned about.
Doctor covers this area with markitdown-sidecar and markitdown-sandbox. The first reports the converter’s version, or says it was not found next to the CLI and that document conversion produces stubs until it is installed. The second reports fail when no usable operating system sandbox is available, which blocks conversion entirely, and warn when conversion is running unsandboxed by explicit opt-in.
There is a setting for the no-sandbox case, off by default: Allow unsandboxed conversion, under the same Advanced group. Leave it off unless you trust every document you import, because the alternative is parsing untrusted files with your full account privileges. The environment variables JOTURA_DISABLE_SANDBOX and JOTURA_ALLOW_UNSANDBOXED_CONVERSION have the same effect for CLI runs, and doctor surfaces either one as a warning. More on the import pipeline in Documents and Documents from the CLI.
Making sense of a CLI exit code
Errors from the CLI are always a single-line JSON object on stderr, whether or not you passed --json. The code field is stable and is the thing to branch on.
| Code | Symbol | Usual cause here |
|---|---|---|
| 1 | Error | Unclassified failure. Read the message field. |
| 2 | HashConflict | The --if-hash precondition did not match. Re-read and retry. |
| 3 | NotFound | File missing, a --replace needle matched nothing, or sync drop-path found no synced row. |
| 4 | Ambiguous | A --replace needle matched more than once. Add --all or --nth N. |
| 5 | OutOfRange | A line number or range is out of bounds, or --nth N exceeds the occurrence count. |
| 6 | NoVault | No vault resolved. Pass --vault, set $JOTURA_VAULT, or open a vault in the app. |
| 8 | PermissionDenied | A filesystem permission error, or a path that resolves outside the vault. |
| 9 | InvalidArgs | A bad flag combination, a wrong sync password, --in with a semantic mode, or trash empty without --force. |
| 11 | MultiEditOpFailed | One operation in an edit --apply or batch sequence failed. |
| 12 | SyncNotEnabled | sync login, sync logout, or sync drop-path on a vault with no sync. |
| 13 | SemanticUnavailable | Semantic search has not been enabled in the desktop app. |
| 14 | TargetMissing | The write target was deleted or moved since the read. |
| 15 | ReadOnlyShare | The target sits inside a share where your role is viewer. |
| 16 | AgentConflict | An agents sync found files changed on both sides. |
Three of those need more than a row.
Exit 11 is fully atomic only for edit --apply. For a batch file it is guaranteed only for failures caught during the planning phase. Once the apply phase has started, a mid-batch failure leaves already-committed operations in place and does not roll them back.
Exit 16 is not an abort. An agents sync completes all non-conflicted work first, then exits 16 with a conflicts array naming only the files it skipped. Re-run with --prefer vault or --prefer system to resolve those, for that run only. See The agent surface.
Argument parsing errors also exit 2, the same code as HashConflict, and this produces genuinely confusing debugging sessions. A missing required argument, an unknown flag, or supplying zero or two operation selectors to jotura edit all exit 2 with plain human-readable text on stderr rather than the JSON error envelope. Before concluding that you hit a hash conflict, check whether stderr actually parses as JSON.
The complete table, including every extra field each error code carries, is on Exit codes and JSON output.
Where to go next
If none of the above matches what you are seeing, run jotura doctor and copy the diagnostics bundle from Settings before reporting the problem. Between them they capture the vault path, sync and share state, document conversion counts, semantic index status, and the recent log lines, which is almost everything needed to reproduce a report. Nothing in either is transmitted anywhere, so you decide what to paste and where.
If you are new to the app and something simply is not where you expect it, Getting started and Keyboard shortcuts cover the ground this page assumes.