Skip to main content
A comprehensive guide to diagnosing and resolving the most common issues you’ll encounter when working with FinWatch. Each section describes the symptom, the likely root cause, and the fix.

Rule Not Triggering

Your rule is deployed and compiled, but transactions that should match it aren’t producing verdicts.

Symptom: Rule compiles successfully but never fires

Cause 1: Field name typo The most common cause. The dig() function silently returns nil for non-existent fields, causing the condition to evaluate to false without any error.
How to diagnose: Log the raw transaction JSON and verify the exact field names. Pay special attention to:
  • amount vs ammount
  • metadata vs meta_data (FinWatch uses metadata internally, but the JSON field is meta_data)
  • Nested field paths: metadata.destination_country requires the transaction to include "meta_data": { "destination_country": "US" }
Cause 2: Wrong operator Using == when you mean !=, or > when you mean >=:
Cause 3: Type mismatch The field value is a string but you’re comparing it as a number, or vice versa:
How to diagnose: Check the raw JSON to see whether the value is quoted ("1") or unquoted (1). FinWatch’s toFloat() function can parse string numbers, but the behavior depends on the comparison operator. Cause 4: Aggregate returning 0 Aggregate functions like count() and sum() query historical data in DuckDB. If the database has no historical transactions (e.g., fresh deployment, no watermark sync), aggregates will always return 0.
How to diagnose:
  1. Check if historical data exists: curl http://localhost:8081/instructions should show your rules.
  2. Inject several test transactions first to build up history.
  3. If using BLNK_DSN, verify the watermark sync is running and data is flowing.
Cause 5: $current placeholder not resolving If the current transaction is missing the field referenced by $current.*, the placeholder resolves to nil and the filter matches nothing:
How to diagnose: Ensure the transaction payload includes the field referenced by $current. A transaction with an empty source field will resolve differently than one where the field is missing entirely.

Parse Errors

FinWatch logs parse errors when a .ws file cannot be compiled. The error includes the line number, column number, and a description.

Common Parse Errors and Fixes

Error: expected verdict (allow, block, review)
Cause: The first token after then is not a recognized verdict. Valid verdicts: allow, block, review, approve, deny, alert

Error: expected number after 'score'
Cause: The value after score is not a valid number.

Error: expected string after 'reason'
Cause: The reason is not wrapped in double quotes.

Error: unexpected token in then clause
Cause: An unrecognized keyword appears inside the then block. Only score and reason are valid after the verdict.

Missing Braces

Unterminated String


Performance Issues

Symptom: High latency on POST /inject

Cause 1: Large aggregate time windows Aggregate functions with large time windows ("P30D", "P7D") scan more data. The larger the window and the more transactions in DuckDB, the slower the query. Fix:
  • Use the smallest time window that meets your detection needs.
  • Apply the gate-and-probe pattern: put cheap conditions before aggregates in your and chain.
Cause 2: Complex regex on long fields Regular expressions on long description fields or large metadata values can be slow. Fix:
  • Keep regex patterns simple. Use alternation (a|b|c) instead of complex nested groups.
  • Anchor patterns with ^ or $ when possible.
  • Gate regex checks with a cheap condition first.
Cause 3: DuckDB memory pressure If DuckDB’s working set exceeds the configured memory_limit, it spills to disk, dramatically slowing queries. Fix:
  • Increase FINWATCH_MEMORY_LIMIT (e.g., from 2GiB to 4GiB or 8GiB).
  • Ensure the temp directory (blnk_agent/duckdb_temp/) is on SSD storage.
  • Implement data retention: delete old transactions that are no longer needed for rule evaluation.
Cause 4: Too many rules with unique aggregates Each unique aggregate (metric, time_window, filter_field, filter_value) tuple generates a separate SQL query. If you have 50 rules each with different aggregate configurations, that’s 50 SQL queries per transaction. Fix:
  • Consolidate rules that check the same metric. If multiple rules check count(when source == $current.source, "PT24H"), the batch aggregate context only queries once.
  • Review your rule set and eliminate redundant or overly specific rules.

Data Sync Issues

Symptom: Watermark sync not advancing

Cause 1: PostgreSQL connection failure The BLNK_DSN connection string is incorrect or the database is unreachable. How to diagnose: Check the logs for PostgreSQL connection errors:
Fix:
  • Verify the connection string: postgres://user:password@host:5432/dbname?sslmode=disable
  • Check network connectivity between FinWatch and the PostgreSQL host.
  • Verify the database user has SELECT permissions on the required tables.
Cause 2: Schema mismatch The PostgreSQL schema has changed (columns renamed, tables dropped) but the sync query still references the old schema. How to diagnose: Check logs for SQL errors referencing specific columns or tables. Fix:
  • Ensure the PostgreSQL schema matches what FinWatch expects.
  • Check the watermark sync configuration for the correct table and column names.
Cause 3: Watermark stuck at old timestamp The watermark advances based on the created_at timestamp of synced records. If new records have timestamps older than the watermark (e.g., backdated transactions), they’ll be skipped. Fix:
  • Ensure all new records have created_at timestamps that are greater than or equal to the current time.
  • If backdated records need to be synced, reset the watermark by deleting the sync_watermark entry in DuckDB.
For detailed sync mechanics, see the Watermark Sync Documentation.

Memory Issues

Symptom: DuckDB exceeding memory limit

How to diagnose: Watch for log messages about memory pressure or check container memory usage:
Cause 1: Memory limit too low for transaction volume As your transaction volume grows, DuckDB needs more memory for its buffer pool and query execution. Fix: Increase the memory limit:
Also increase the Docker/Kubernetes memory limit to accommodate the Go runtime overhead (add 1-2 GB above the DuckDB limit):
Cause 2: Temp directory on insufficient storage When DuckDB spills to disk, it writes to blnk_agent/duckdb_temp/. If this directory runs out of space, queries fail. Fix:
  • Ensure the temp directory has at least 2x the memory_limit in free disk space.
  • Mount the temp directory on SSD for better spill performance.
Cause 3: Long-running aggregate queries Aggregate queries over very large time windows ("P30D" on millions of transactions) can consume significant memory during execution. Fix:
  • Reduce time windows where possible.
  • Add simple condition gates before aggregate checks.
  • Consider whether you need the full 30-day window or if 7 days would be sufficient.

Connection Issues

Symptom: Port conflict on startup

Cause: Another process is already using port 8081. Fix:

Symptom: WebSocket tunnel disconnections

Cause: The connection to the Blnk Cloud dashboard has been lost. This can happen due to network interruptions, server restarts, or firewall changes. Impact: Anomaly notifications are not sent to the dashboard. Transaction processing continues normally — verdicts are still computed and logged locally. Fix:
  • The tunnel automatically reconnects. Check if reconnection is happening by monitoring logs.
  • Verify outbound HTTPS connectivity from the FinWatch server to the Blnk Cloud endpoint.
  • Check firewall rules for WebSocket (wss://) connections.

Symptom: API timeouts from your application

Cause: FinWatch is taking too long to respond to POST /inject requests. Fix:
  1. Check if the issue is consistent or intermittent. Intermittent timeouts usually indicate DuckDB memory pressure or spill-to-disk.
  2. Review the Performance Issues section.
  3. Set appropriate timeouts in your application (recommended: 5 seconds).
  4. Implement a fallback: if FinWatch doesn’t respond in time, allow the transaction and log the timeout for later review.

Git Sync Issues

Symptom: Repository clone fails

Cause: The Git repository URL requires authentication that isn’t configured. Fix:
  • For HTTPS repos, include credentials in the URL: https://token:ghp_xxxx@github.com/org/repo.git
  • For SSH repos, ensure the SSH key is available in the container/server.
  • For public repos, verify the URL is correct and the repo exists.

Symptom: Rules not updating after merge

Cause 1: The Git polling interval hasn’t elapsed yet. By default, FinWatch checks for updates every 30 seconds. Fix: Trigger an immediate sync:
Cause 2: The branch configuration doesn’t match. Fix: Verify WATCH_SCRIPT_GIT_BRANCH matches the branch you merged to:

Symptom: Git not installed

Fix: Install Git in the container or on the server:
If using Docker, ensure your Dockerfile includes Git.

Diagnostic Commands

Quick Health Check

Test a Specific Rule

Inject a transaction designed to trigger your rule and watch the logs:

Check DuckDB Data

If you need to verify what’s in the database, use the instructions API to check compiled rules:

Check Transaction Storage

Inject a transaction and verify it was stored:

Getting Help

If you’ve worked through this troubleshooting guide and the issue persists:
  1. Collect logs. Capture the full FinWatch log output around the time of the issue.
  2. Reproduce the issue. Create a minimal .ws rule and a specific transaction payload that demonstrates the problem.
  3. Check the rule JSON. Use GET /instructions to see the compiled JSON representation of your rule. This can reveal issues the .ws source doesn’t make obvious.
  4. Review the DSL Reference. The DSL Reference is the authoritative specification for all syntax and behavior.
  5. Open an issue. If you believe you’ve found a bug, open a GitHub issue with:
    • The .ws rule file
    • The transaction JSON payload
    • The expected behavior
    • The actual behavior
    • FinWatch version and environment details

Next Steps