Troubleshooting
Common situations and how to clear them. When in doubt, run iris validate —
it’s the fastest way to learn what’s wrong.
iris validate reports errors
iris validate checks every file and prints what’s wrong. The usual causes:
- Unbalanced entry — debits don’t equal credits. Fix the amounts so they sum to the same total.
- Unknown account — a journal references an account not in
config/chart-of-accounts.yaml. Add the account to the chart (or use an alias). Don’t invent account paths inside the journal. - Date mismatch — the
date:field doesn’t match theYYYY-MM-DDprefix of the filename. Make them agree. - Bad status —
statusmust bedraftorposted. - YAML won’t parse — usually indentation or a stray colon in the frontmatter. The error names the file.
- Tax classification (JP taxable books) — a
taxblock with an unknown category, or a rate that doesn’t match its category (e.g. ataxable_salewith no rate, or anexport_salewith a non-zero rate).
Fix and re-run. Your AI assistant can do this loop for you.
”I posted an entry but it’s not in my reports”
Reports include only posted entries. If a transaction is missing from
iris balance, the P&L, or the balance sheet, its status is almost certainly
still draft. Promote it:
iris post journals/2026/05/2026-05-04-example-com-01.md
…or edit the status: field to posted and re-validate.
”iris: command not found”
The iris binary isn’t on this machine’s PATH yet. Install it
(curl -fsSL https://irisbooks.jp/install.sh | sh on macOS/Linux,
irm https://irisbooks.jp/install.ps1 | iex on Windows PowerShell), then check
with iris version. If you’re working in a sandboxed AI environment, there is
no copy bundled inside the book — the host runs iris mcp serve and your
assistant calls the verbs over MCP instead.
Sync rejections (needs-attention)
iris validate checks file state, but the server runs additional rules when
you push (chart-projection orphans, a journal referencing a raw/ file that
isn’t uploaded, schema/immutability violations). When the server rejects a
push, iris validate may end with a note like “N file(s) blocked in the sync
queue” — the files are fine, the push was rejected.
To clear it:
iris attention list # read the field-level reason
Then fix the cause — usually:
- add the missing account to
config/chart-of-accounts.yaml, or - make sure the referenced
raw/...document is actually present and synced.
Then re-save the rejected journal. Its content hash changes, the engine drops the per-file suppression, and the push goes out automatically on the next sync.
If your fix was in a different file (e.g. you fixed the chart days ago and won’t touch the journal again), nudge the engine instead:
iris attention retry # re-push everything in the queue
iris attention retry --path <relpath> # just one file
Sync conflicts
If you and someone else (or you on another device) changed the same file, a
push can conflict. The server version takes the canonical path, and your
version is saved beside it as a <file>.conflicted sidecar. iris sync
refuses to proceed while any sidecar exists, so nothing is lost.
iris conflicts list
Resolve each one. The usual way is to merge by hand: open the canonical
file, fold in whatever you need from the .conflicted sidecar, delete the
sidecar, and run iris sync again. To take one side wholesale instead:
iris conflicts resolve <path> --keep mine # replace canonical with your version
iris conflicts resolve <path> --keep cloud # discard your version
iris sync exits with code 3
Exit code 3 means a terminal disconnect. The summary (and the
disconnectReason field of iris sync --json) says which kind:
- deleted — the owner deleted the book on the server (web app →
the book’s Settings → Danger zone). Your local files are intact — nothing was
removed from your folder, and
iris statusshowsRemote: deleted on the server. To keep working locally, editconfig/book.yamland setbook_idback to your local id (iris statusprints it). To reconnect to the cloud, create a new book (iris api books new) and link it (iris api books link <id> --force). - forbidden — your access was revoked (your credential is valid but you no longer hold a grant). Ask the book’s owner to re-invite you. If access was intentionally revoked, that’s expected.
- auth_expired — your session is gone. Re-authenticate
(
iris api login) and runiris syncagain.
”I need to change a sealed year”
A sealed fiscal year is locked: iris post refuses journals dated in it
(“FY <n> is sealed (closed period) — run iris reopen <n> to amend it, then
re-seal”), sync pushes into it are rejected by the server, and the web app
and remote connector refuse edits too. The year’s files stay in your working
tree — they just refuse writes. To amend the year, reopen it first:
iris reopen 2025 # unlocks the seal; the files are already in the working tree
# …make the correction…
iris sync
iris api seal --period 2025 <book-id> # close the year again
The server records the corrections as post-seal edits — visible in the Activity log and badged in the web app. That’s by design: the correction is allowed and auditable, not hidden. Re-sealing supersedes the old seal in the audit chain.
”The web app shows different numbers than my CLI”
Almost always a sync gap or a status difference:
- Run
iris diffto see local changes you haven’t pushed, theniris sync. - Remember the web app, like the CLI, reports only
postedentries — a draft you see locally won’t appear until it’s posted and synced. - Reports in the web app show a “freshness” note for when the server last recomputed; give a recent push a moment to project.
Still stuck?
- Re-read Core concepts — most confusion is about
status(drafts vs posted) or what sync does. - Check the in-book
notes/open-questions.md— your AI files ambiguous items there. - For Japan tax specifics, see Japan tax & compliance; your AI verifies volatile values (rates, tables, form layouts) against the NTA’s current pages.