Troubleshooting
A playbook for the issues that have actually shown up in production, ordered by frequency.
"I forwarded a receipt and nothing happened"
Look at:
- The Discord channel ID + allowlist. Bot only responds in the
exact
DISCORD_CHANNEL_IDfrom Infisical, and only to user ids inDISCORD_ALLOWED_USERS. - The bot container logs:
docker logs prod-accounting-bot --since 5m. Look for ingest pipeline lines starting withaccounting_agent.ingest.pipeline. - If the bot is up but not reacting: gateway connection issue.
/restart-botor justdocker restart prod-accounting-bot.
"Recon was inserted but didn't match my doc"
Usually one of:
- Counterparty mismatch. The bank txn has
counterparty_name=NULLand the matcher can't fire the counterparty signal. Check the recon row in Turso. If description has the vendor name, the EB poller's_counterparty_namefallback should have filled it — if not, the EB poller is on an old image; redeploy. - Date window. Documents older than 21 days from the bank txn date are excluded from candidate search. Either re-ingest the doc with a corrected date or widen the window in the matcher config.
- Score below HITL. Look at the matcher signals via
/inspect-match <recon_id>(if available) or query the candidate scoring directly. Card debits without invoice number in description can still hit 0.44; the boost should pull them to 0.59. Boost isn't firing? Checkamount_exact(zero-cent diff, not 2-cent tolerance).
"Booking failed with e-Fin 409"
9 of 10 409s mean a missing required field in the payload.
e-Fin's error body is verbose; the booker's EFinancialsError
carries the full body. Search Sentry / logs for the response.
Common ones we've hit:
"Please fill required field 'client_name'"— the booker is missingclient_namein the create payload. Should be permanently fixed in commit6299fda."An account must be chosen for each product/service"— the item is missingcl_purchase_articles_id. Should also be fixed."Entry cannot be made directly to the account X since it has dimensions"— the item is missingpurchase_accounts_dimensions_id. The booker fetches this from the article record (dimensions__id); if it's not being passed, check_get_purchase_articleis finding the article.
If you see a NEW 409 the codebase doesn't recognise: log the full
e-Fin body and check the OpenAPI spec at
https://demo-rmp-api.rik.ee/openapi.yaml.
"e-Fin returned 500"
Less common. e-Fin's API occasionally leaks Postgres errors as
500s (the cl_fringe_benefits_id NOT NULL constraint surfaced
this way). The body contains a Python traceback — read it.
The retry layer catches transient 5xx (3 attempts, exponential backoff). Persistent 500 = real validation problem masquerading as a server error.
"VAT decision returned 'unknown'"
Either:
- No applicable rules in the SQL
tax_rulestable for this jurisdiction pair. Check/rules supplier_country=X. If empty, upload the relevant tax PDF and re-ingest askind=tax-rule. - FalkorDB is unreachable. Logs will show
redis.exceptions. ConnectionError: Error -3 connecting to prod-falkordb:6379. The decision falls back to SQL-only; confidence may be lower but the booker still functions.
If both layers are populated and decision is still 'unknown',
the LLM didn't find enough context. Try /vat-decision manually
with the same arguments + extra context in the prompt; if it
still struggles, the rule set genuinely has a gap.
"Booker is stuck on the same row across multiple ticks"
Most likely cause: a HITL gate has fired but the Discord prompt never posted (or the prompt posted but isn't being seen). Check:
SELECT * FROM agent_checkpoints
WHERE status = 'pending'
AND kind IN ('booker_approve', 'client_create_approval')
ORDER BY created_at DESC;
If a checkpoint exists with prompt_message_id IS NULL, the bot
hasn't posted it yet — the bot's BookerHitlPoller ticks every
300s, so wait or restart the bot.
If prompt_message_id is set but you don't see the message in
Discord: scroll up; sometimes notification settings hide them.
"I want to undo something the booker did"
You can't, easily. e-Fin entries in REGISTERED state are
journaled — undoing requires either a manual e-Fin UI action
(Void confirmation → edit → re-register) or a counter-entry by
your accountant.
The agent's contract is "never write something you can't audit back to a Discord approval." That's protective, not punitive — but it does mean accidental approvals turn into permanent journal entries.
When in doubt
- Look at the Discord channel last hour
docker logs prod-accounting-booker --since 1h- Query Turso for the affected recon row
- Check Sentry for unhandled exceptions
90% of issues are visible at one of those four checkpoints.