Skip to content

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:

  1. The Discord channel ID + allowlist. Bot only responds in the exact DISCORD_CHANNEL_ID from Infisical, and only to user ids in DISCORD_ALLOWED_USERS.
  2. The bot container logs: docker logs prod-accounting-bot --since 5m. Look for ingest pipeline lines starting with accounting_agent.ingest.pipeline.
  3. If the bot is up but not reacting: gateway connection issue. /restart-bot or just docker restart prod-accounting-bot.

"Recon was inserted but didn't match my doc"

Usually one of:

  • Counterparty mismatch. The bank txn has counterparty_name=NULL and 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_name fallback 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? Check amount_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 missing client_name in the create payload. Should be permanently fixed in commit 6299fda.
  • "An account must be chosen for each product/service" — the item is missing cl_purchase_articles_id. Should also be fixed.
  • "Entry cannot be made directly to the account X since it has dimensions" — the item is missing purchase_accounts_dimensions_id. The booker fetches this from the article record (dimensions__id); if it's not being passed, check _get_purchase_article is 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_rules table for this jurisdiction pair. Check /rules supplier_country=X. If empty, upload the relevant tax PDF and re-ingest as kind=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

  1. Look at the Discord channel last hour
  2. docker logs prod-accounting-booker --since 1h
  3. Query Turso for the affected recon row
  4. Check Sentry for unhandled exceptions

90% of issues are visible at one of those four checkpoints.