Skip to content
Connect > Data APIs

Troubleshooting the Data APIs

Most first-time failures come down to one of two things: a surface that is still disabled, or a filter written in ANSI SQL instead of AMI expression syntax. This page lists the errors you are likely to see and what each means.

The "it's disabled" traps

Symptom Cause Fix
/3forge_rest/query returns 404 with Endpoint not found: /query and a list of the loaded endpoints, but /3forge_rest/stats works The QUERY endpoint is not loaded (shipped default *,!QUERY,!ADMIN) Add QUERY to ami.rest.plugin.classes and restart. See Configuration.
WebSocket connection is refused / port not listening The WebSocket server never started Set ami.websocket.port and restart. The log will confirm.
Log says WebSocket server disabled (no ami.websocket.port configured) ami.websocket.port is unset Set it in local.properties.
Response body: Rest not enabled on this port The REST server is not bound to the port you called Check ami.rest.uses.web.port / your standalone REST port.

REST errors

Message / status Meaning Fix
cmd required The /query request had no cmd parameter Supply cmd=<command>.
unknown center: <db> (existing centers: …) The db parameter names a Center that isn't running Use one of the listed names, or omit db for center.
display must be either: text, pipe, jsonMaps, json, jsonRows The display value is wrong. It is case-sensitive: jsonmaps fails, jsonMaps works Use one of the five exact spellings.
HTTP 400 with a plain-text or HTML body and no status field A request error (missing cmd, unknown db, bad display): a different shape from statement errors Check the HTTP status before calling resp.json(); see REST API → Four kinds of error.
HTTP 500 with REQUEST TIMEOUT ERROR or UNKNOWN ERROR FROM AMI REST PLUGIN The request timed out on the server or failed unexpectedly; the body is plain text, with a stack trace unless ami.rest.show.errors=false Check the HTTP status before parsing; for a timeout, narrow the query or check the Center's load.
error: {message, atLine, atChar} in a JSON response (HTTP 200) The command reached the Center but failed; atLine/atChar are 0-based Fix the SQL at the reported position.
rowsAffected:0 on a write you expected to change a row rowsAffected counts changed rows, not matched: an upsert over an existing key, and a no-op or zero-match UPDATE, all report 0 Use status == "ok" for success, not rowsAffected.
A table exists but SELECT returns no rows after a restart Rows are not persisted without a PersistEngine; the table definition survives a restart, the data does not Reload the data, or create the table with a PersistEngine. See Concepts.
HTTP 401 with WWW-Authenticate: Basic Not authenticated Send Basic credentials (curl -u user:pass) or a valid session cookie.
HTTP 403 Authenticated but disabled, locked, or over a limit Check the response body text: SERVICE_DISABLED, ACCOUNT_LOCKED, or USER_COUNT_EXCEEDED.

The limit behind USER_COUNT_EXCEEDED is a licensed cap on distinct (host, username) pairs that have logged in through the Web, JDBC, or the console, not a per-request or per-second rate. The count is cumulative since the process started: a pair is not released when its session ends. REST calls that authenticate with Basic credentials are not counted. Check the current count against the cap with SELECT UniqueUsers, MaxUsers FROM __STATS. The cap comes from the license (USERS= in the license string); an unlicensed instance defaults to 1000. There is no property to raise it; it requires a new license.

WebSocket errors

Symptom Meaning Fix
Connection is refused or times out before it opens The WebSocket server is not enabled (no ami.websocket.port), or the host/port is wrong. There is no client-facing "is it up" endpoint A refused port means the server never started: set ami.websocket.port and restart. This is distinct from a connection that opens then closes with unknown component (server up, wrong path).
First connect after a process restart hangs ~2 s, then works First-connection warm-up Give the initial connect a generous timeout; don't treat a couple of seconds of silence as failure or reconnect-loop on it.
Connection closes with unknown component: X (existing: ...) The URL path names a Center/Gateway that isn't registered Use a listed name; confirm that Center is running.
Subscribe returns an error frame starting bad request: The frame itself was rejected: an unknown action, or sql that is not a SELECT Send "action":"subscribe" with a SELECT. Writes are not possible here; send them over REST.
Subscribe returns subscribe failed: authentication required The path names a Gateway that authenticates subscribers (the default), and the connection carried no credentials Connect with credentials in the URL: wss://user:pass@host:3410/<gateway>. A browser sends them only if ami.websocket.auth.plugin.class names an authentication plugin; with DISABLED it never does.
An error frame whose message starts upstream: The upstream Center or Gateway reported an error, such as a Gateway refusing the forwarded login Read the rest of the message; for a refused login, check the user against the Gateway's authentication source.
subscribed and snapshot arrive, then no rows ever The table does not exist, or is not PUBLIC. An unknown table is acknowledged, not rejected Check the name with SHOW TABLES over REST, and confirm the table is PUBLIC.
A column is missing from every row you receive That column does not exist on the table. Unknown columns are dropped silently Check the column names against the table definition.
The filter has no effect: every row arrives, including rows it should exclude, and then no updates ever follow The WHERE is not a boolean expression, usually because it was written in ANSI SQL with a single =. A WHERE the Center cannot evaluate is not reported: the initial load is unfiltered and the subscription receives no further changes Use == and double-quoted strings: SYM == "IBM", escaped \" inside the JSON.
A filtered row never disappears after it should leave the filter Focus filtering is off Subscribe with oof:true to get delete when a row stops matching.
Connection closes with status 1009 and reason message too large right after sending a large message An inbound message exceeded the size limit: 1 MB for a single frame, or ami.websocket.max.message.bytes (default 1 MB) for a message split across frames Send smaller messages.
wss:// closes immediately with status 1006 from a browser The browser doesn't trust the server certificate, or client-cert mTLS is on with no client cert Import/trust the server cert (or front with a proxy); for browser access leave the authorized-clients file unset.
Browser can't authenticate on the handshake Browsers can't set the Authorization header Put credentials in the URL (wss://user:pass@host:3410/center); the browser sends them after the server's 401 challenge. Or run with auth DISABLED behind a proxy.

A subscription is acknowledged even when it cannot work

The server checks only that action is known and that sql is a SELECT. An unknown table, an unknown column, and a WHERE it cannot evaluate are all accepted, with no error frame. A subscribed acknowledgement means your frame parsed, not that your subscription matches anything.

This matters most where the filter is the condition being watched, as in the limit-breach alert: an ANSI WHERE breached = true loads every limit, breached or not, and then never reports a change, so the monitor raises alerts that are not real and misses the ones that are. Test a filtered subscription against a row it should exclude, not only against one it should include.