Troubleshooting
The symptoms operators actually hit — a market that reads ACTIVE and prints nothing, a start that is refused, a pool that will not fund or withdraw, disagreeing volume figures and a price being driven twice — with the cause and the fix for each.
Work down this page in order. Most reports resolve at the first two checks.
Quick diagnostics
- Admin → System → Extensions —
ai_market_makerenabled, andecosystemenabled - Admin → System → Cron — seven jobs under
ai_market_maker, none failed - Dashboard masthead — an engine process is named, and leadership is arbitrated by Redis or the database
- Dashboard quoting meter — the market says Quoting, not Not quoting with a gate named
- Market detail → Overview — the last known price is changing
- Server log, filtered to
AI_MM— the engine states its own refusals there
The market says ACTIVE and nothing is happening
This is the single most common report, and the status column is not the answer. The engine applies four hard gates and a market failing one keeps its ACTIVE badge.
A print needs two sides. Open the market's Bots tab and count the ACTIVE ones. The dashboard names this as "needs active bots" and links to the market.
Log line: Need at least 2 active bots for SYMBOL, have: 1
Note that a bot can only be activated while its market maker is ACTIVE — if you stopped the market and paused bots individually, activate the market first.
With realLiquidityPercent above 0 and a total value locked of zero, there is
nothing to back an order. Either fund the pool or set real liquidity to 0.
Log line: Real liquidity enabled but no pool for SYMBOL
currentDailyVolume has reached maxDailyVolume. The market stops quoting until
the UTC daily reset. Raise the budget, or use Reset daily counters on the
Configuration tab to hand out a fresh allowance now — understanding that the
budget existed for a reason.
Log line: Daily volume limit reached for SYMBOL: x/y
This gate is not visible on any screen. It is evaluated from price history held in the engine's memory, which no query can reach, so the dashboard will still report the market as quoting.
Log line, throttled to once a minute:
High volatility (x.xx%), skipping SYMBOL
Either raise volatilityThreshold on the market, lower baseVolatility, or turn
pauseOnHighVolatility off.
Global Pause or Maintenance Mode on the settings screen suppress trading across every market. Prices and charts keep advancing, which is exactly what makes this one hard to spot: the chart looks alive and the tape is empty.
A market will not start
totalValueLocked is zero. Deposit to the pool first — see
Funding the pool.
aiMarketMakerMinLiquidity is checked against the pool's quote balance, not
its TVL. A pool holding plenty of base and nothing in quote fails this. Deposit
quote, or lower the setting.
The engine may not be running in the process that answered. The response says so: "recorded as ACTIVE, but the market-making engine is not running in this process yet." Wait one engine cycle. If it never starts, check the cron registry and the leadership block on the dashboard.
The setting labelled Max Concurrent Bots actually caps the number of markets the engine will drive. Raise it on the settings screen. The dashboard also raises an alert when the engine holds fewer markets than the database says are ACTIVE, which is the same fault seen from the other side.
The market maker has no bot rows at all. This should not happen — six are created in the same transaction as the market — but a partially rolled-back creation on an old build could produce it. Delete and recreate the market maker.
No ecosystem markets to select
The create wizard offers only ecosystem markets that do not already have a market
maker. A pair that already has one will not appear — the marketId column is
unique and the API refuses the duplicate with "AI Market Maker already exists for
this market".
If the list is empty entirely, you have no ecosystem markets. Create one under the Ecosystem addon first.
The pool will not fund or will not release
Pause or stop the market first. The same guard applies to the rebalance calculation, in both REPORT and EXECUTE modes.
An older build could leave a market the engine had lost in a state where stop reported success without changing anything and pause returned a server error — which locked the pool, because withdrawals refuse an ACTIVE market. Update. Both actions record the change properly now, and stopping also clears any synthetic depth left on the order book.
A build before v6.1.5. The wallet ledger key was derived from (pool, currency)
alone, so a pool could be funded exactly once per currency, ever — and whatever
was left after a first withdrawal could never be taken out. Update; no data is
lost.
Funding is an internal transfer between two balances the platform already holds. An older build routed it through the deposit-address machinery, so an admin holding a good balance in a token whose chain was not configured on that server could never fund the market. Update.
The price is wrong or is moving twice as far
Symptoms that all have this one cause: the price moves roughly twice as far as configured; stopping a market from the admin panel leaves it publishing; synthetic order book levels reappear after being cleared; the 1-minute candle disagrees with itself.
The engine must tick exactly once per deployment. Check the dashboard's engine
block: if leadership is arbitrated by "none", neither Redis nor the database
lease row could be reached and every process that starts the engine believes it
leads. Restore Redis, or the ai_market_maker_engine_lease table, and restart.
Cluster mode, a rolling restart whose old worker has not exited, and two development shells all produce this.
Other price symptoms:
- A step change on every chart after a restart — a build before v6.1.5, which kept no price state and began each start on a fresh path, seeded around the configured target rather than the live price. The engine now checkpoints every two minutes and resumes.
- "No price yet" on a market you just started — expected. The first checkpoint is a couple of minutes out.
- The price leaves its band — the containment force engages only in the outer 20% of the range. If the market sits at the edge, widen the range; the dashboard reports at range edge as its own state so you can act before it leaves.
Figures that disagree
currentDailyVolume is zeroed at the UTC daily reset. It is volume today, not
a rolling day. This is normal and the dashboard labels it accordingly.
By design. The dashboard sums every market whatever its status; the analytics screen still sums ACTIVE markets only. Pausing a market part-way through a day removes it from the analytics figure along with the volume it had already traded.
A trade between two of the platform's own bots has no profit or loss — both sides are the house. On a market at 0% real liquidity, realised P&L is legitimately zero however busy the tape looks.
Different ledgers. All-time comes from each bot's lifetime accumulator; the period figures come from a per-fill ledger that had no writer until v6.1.0, and the individual fills before that were never captured. The screen states when the ledger begins.
Every summary written before v6.1.5 recorded zero volume, zero buys and zero sells, for the server's local day rather than the UTC day. Summary history cannot be deleted, so those rows remain. Everything written since is correct.
A build before v6.1.5, which reported 50% on the list and 65% on the detail screen with the counts derived from the rate. None of it was measured. Update; those screens now show blanks where there is nothing to measure.
Orders pile up in the Ecosystem book
The backend loads open orders at startup. A build before v6.1.5 never cancelled its own quotes — one live market reached 704,353 open orders, which was enough to make the site serve connection refused while the log filled with successful startup messages.
Update, then clean up. Orders already resting do not disappear on update:
pnpm eco:mm:orders # report what is there
pnpm eco:mm:orders:clean # cancel themThe cleanup reads each order's true owner from the ecosystem row itself, which is why it can cancel rows the engine cannot.
If a current build warns that a market is at its resting-order ceiling:
N real liquidity orders are already resting, at the ceiling of 500.
That is the ceiling working. It means quotes are not being cancelled — check the
expiry sweep in the log before raising maxRestingRealOrders or
AI_MM_MAX_RESTING_REAL_ORDERS.
Real users' orders vanish from the book
Fixed in v6.1.5. Every AI trade used to rebuild the market's aggregated order book by deleting every level for that symbol and writing its own back — taking real users' resting limit orders, and copy-trading followers', with them. They reappeared minutes later when a repair pass ran. While a level was missing it could not be matched against, and anything pricing off that book read the same gap.
The menu entry is missing
Admin → System → Extensions. With the row off, no menu entry renders and no cron registers.
The addon's keys were renamed from a dotted spelling (ai.market.maker) to an
underscored one (ai.market_maker), and the migration deletes the old rows.
Grants carry over for most of the family, but access.ai.market_maker.market —
the Markets list screen — receives grants from a retired ai.trading.market
family rather than from the addon root. Re-grant the underscored key.
Super Admin bypasses the gate outright, so an owner testing their own admin account sees nothing wrong.
Cron jobs are missing or doing nothing
The extension row is off. The scheduler reads the enabled-extension set from the database and registers addon jobs from it.
The ecosystem extension is disabled, so no process in the deployment boots an
ecosystem matcher. The market maker trades ecosystem markets, so there is nothing
to quote — this is not about which process cron runs on. The other six jobs still
run and are unaffected.
Correct behaviour under CRON_MODE=only. The engine's bots enqueue into the
ecosystem matcher, so the job runs where the matcher does — the web process
drives the same handler from its own supervisor tick.
A build before v6.1.5. The pool rebalancer and the external price sync both required the global trading switch to have been explicitly saved once, and it is not set on a fresh install. Every other job already treated an unset switch as on. Both now do the same.
Configuration changes have no effect
Before v6.1.5, changing a market's volatility, bias, price mode, target price, price range or forced phase — or any of a bot's settings, or its status — showed a success message, updated the database and left the running market behaving exactly as before until the next full reload, which in practice meant up to 24 hours.
A second defect sat behind it: the engine replaced its configuration wholesale on refresh while the parts that place orders and execute trades still read the copy handed to them at startup. That is why Max Daily Volume and the per-bot trade limits stopped being enforced once a market's configuration had been touched at all.
If bot edits in particular are not sticking, see the warning on Bots — the old form posted field names the server does not read, and nine of the ten risk-tolerance slider positions were refused outright, taking the rest of the request with them.
Every emergency stop in history says the same thing
The dashboard's button posted an empty request to an endpoint that has always accepted a reason and has always written it onto each market's history entry. So every such entry already recorded reads "Emergency stop triggered by admin". Those rows cannot be reconstructed. From v6.1.6 the dashboard requires a written reason; the panel on the settings screen still does not.
Collecting information for support
Have these ready:
- The addon version, from Admin → System → Extensions.
- Whether
ecosystemis enabled, and whether Scylla is reachable. - The dashboard's engine block — process, leadership and what arbitrated it.
- The affected market's quoting state and, if it is not quoting, the named gate.
- Server log lines tagged
AI_MM,AI_MM_WSorAI_RISK_MONITORaround the time of the problem. - The market's recent history entries, which name every configuration change and who made it.