Skip to main content

Troubleshoot Analytics

Most problems appear when you save a query, not when you run it. Knowing which of the two happened rules out half the possible causes immediately.

Start with three checks​

  1. Confirm the query saved at all — a query that will not save has a validation problem, not a data or access problem.
  2. Confirm the app owns what the query names: its data tables for an internal query, its connection secret for an external one.
  3. Confirm you supplied a value for every caller placeholder. There are no optional placeholders.

A query will not save​

These are validation failures, returned as 400. They describe the query text or its configuration and never depend on your data. The specific message is under errors.query_text, errors.secret_key, or errors.description in the response, and a suggested fix, when there is one, is in detail.

Statement and table problems​

MessageWhat it meansFix
Unknown table(s) for app '<slug>': <names>An internal query names a table that is not a data table of this appCheck the name in Datatables. A table in a different app reads as unknown here, not as a permission error
The query's tables could not be resolved: …Analytics could not work out which tables an internal query reads, so it refused the query rather than allow itSimplify the statement, for example by moving a nested query into a WITH clause
Only a single statement is allowed in analytics queries.The query text contains more than one statementSend one statement
Only SELECT queries are allowed in analytics. …The statement is not a read, or contains a write such as INSERT, UPDATE, DELETE, MERGE, or SELECT ... INTO anywhere inside itSend one read statement
Function '<name>' is not allowed in analytics queries.The query calls a blocked functionRemove the function call
Cross-schema access is not allowed for internal analytics queries …An internal query names a schema other than the site's ownRemove the schema name and use the table's logical name
Invalid SQL syntax: … or Query text could not be read as <dialect> SQL.The statement cannot be read in the connector's SQL dialectCorrect the syntax for that database

Placeholder problems​

MessageWhat it meansFix
Query placeholder {{ x }} is inside quotation marks.The placeholder is only part of a quoted text, such as '%{{ x }}%'Build the text in SQL, for example concat('%', {{ x }}, '%'). A placeholder that is the whole quoted text, '{{ x }}', is accepted
Query placeholder {{ x }} is written as a quoted identifier. or A placeholder stands in for a value, not for a table name.The placeholder is used as a column or table nameName the column or table in the query text
Query placeholder {{ x }} is immediately followed by a '::' cast.A :: cast is written directly after the placeholderWrite cast({{ x }} as int), or put a space before ::
Query placeholder {{ … }} is not a plain value reference.The placeholder contains a filter or expression, such as {{ x | default('open') }}Name one value and do any transformation in SQL
Query text contains a template control block …The text contains {% … %} or {# … #}Remove the block; write a separate query for each variant
Query placeholder {{ secret }} refers to the secret namespace as a whole.The placeholder names the secret store instead of one secretName one secret, such as {{ secret.region_filter }}
Secret placeholders are only allowed in WHERE, JOIN ... ON and HAVING conditions.A stored secret sits in the returned columns, an ORDER BY, or another position that is not a filterMove it into a filter. The built-in user profile is not limited this way

Connection and secret problems​

MessageWhat it meansFix
Secret key is required for external database connections.The query is external but names no connection secretName a secret, or switch the query to internal. External is the default, so a query declaring no mode lands here
Secret '<key>' was not found for this tenantThe connection secret does not exist for this site and appCreate the secret, or check whether it was stored against a different app
Secret type '<slug>' is not a supported analytics …The connection secret exists but its type sits outside the analytics setCreate a secret of the matching analytics type — the type selects the connector
Referenced secrets not found: <names>A secret. placeholder in the query text names a secret that does not exist for this site and appCreate the secret, or correct the name
Description must be at most 1000 characters.The description is longer than 1,000 charactersShorten the description

Elasticsearch body problems​

MessageWhat it meansFix
Elasticsearch query_text must be valid JSONThe body is not valid JSON, which includes a placeholder written outside a JSON stringCheck for a trailing comma or an unquoted key, and put every placeholder inside quotation marks
'<key>' is not allowed in analytics queries for security reasons.The body contains a script or runtime_mappings key at some depthRemove the key
A placeholder cannot be used as a key: …A placeholder is used as a JSON keyWrite the key in the body and use the placeholder only as a value

An edit to an older query is refused​

Every edit re-runs all save checks, even an edit that only renames the query or changes its tags. A query saved before a check existed is refused on its next edit if its text breaks that check — for example, a | default(...) filter, a placeholder that is only part of a quoted text, or a stored secret in the returned columns. Fix the query text in the same edit, using the tables above.

A placeholder problem in an older query also stops it from running, because each run reads the placeholders with the current rules. The run fails with the same message listed under Placeholder problems.

A query saves but fails to run​

These depend on values, data, or connectivity, so they only appear at execution. They come back as HTTP 400 with code BAD_REQUEST. The cause is in message, and a suggested fix, when there is one, is in detail.

MessageWhat it meansFix
Query placeholder {{ x }} has no value.The run did not supply a value for a caller placeholderSend every placeholder's value in params
Query placeholder {{ x }} was given an empty list.A list parameter had no itemsSend at least one item, or skip the run
Secret '<name>' referenced by query '<slug>' was not foundA secret. placeholder names a secret that was deleted after the query was savedRecreate the secret, or edit the query to stop referencing it
Do not pass secret.* in params; …A parameter name starts with secret.Remove it; secrets are read from storage, not sent by callers
secret.user_profile requires an authenticated user.The query uses the built-in profile but the caller is not signed inRun the query as an authenticated user
Query placeholder {{ secret.x.y }} refers to 'y', which does not exist in that value.The secret's stored JSON has no such fieldCorrect the field name or the secret's value
Query returned … rowsThe result exceeded the connection's row maximumAdd a row limit — LIMIT for SQL and internal queries, size for Elasticsearch — or aggregate instead of returning individual rows. See Bound every query
A type error from the database naming a value you suppliedThe value's type does not fit where the placeholder sits, for example text compared with a number column. The wording comes from the database itself, so it varies by connectorSend the value in the type the column expects, or cast the placeholder in SQL
A missing-relation error for a table that does existThe data table was renamed or removed after the query was saved, so its logical name no longer resolvesUpdate the query to the table's current name
A connection failure reported by the databaseThe database refused the connection or was unreachable. It returns 400, like a query error, so tell the two apart by the message. For an internal query the message starts Internal DB query failed:For an external database, confirm the host, port, and credential are still valid; for an internal query, retry and report it if it persists. Analytics applies best-effort redaction, but the returned provider message is not a complete sanitization boundary; review it before sharing

Results are not what you expect​

Nothing failed here — the query ran and returned results that are not what you expected.

SymptomWhyWhat to do
Aggregation rows come back instead of documentsAn Elasticsearch query containing aggregations returns the aggregation outputRemove the aggregations to retrieve documents. Each row identifies the aggregation it came from
A per-user query returns nothingThe query filters on the built-in caller profile, which returns only that caller's rowsConfirm the request is authenticated, and that the compared value matches how the data actually stores it
The result count looks wrong for a searchFor an Elasticsearch search, the reported total counts matching documentsRead it as documents matched, which is not necessarily the number of rows returned

Access is refused​

Running a query has two 403 refusal paths, and the message tells you which check stopped the caller. A member of the organization that owns the site is allowed without these checks; any other user must pass both. These checks apply only to running a query; see who can manage a query.

No app roles assigned means a site user holds no role at all on the app that owns the query. It is checked on every run, before the query is read.

You do not have permission to execute query '<slug>' means the caller does hold a role on the app, but someone has since edited this specific query's policy to name which roles may run it, and the caller's role is not among them. No query starts out restricted this way, so this message means someone deliberately locked this one down — check its policy rather than assuming a general fault.

See Who can run and manage queries for both checks and how to set the second one.

Analytics is unavailable for the site​

A 402 with a message about the account not being active means the organization's account is suspended. Every analytics request is refused while that lasts — running a query and managing query definitions alike — so this is a billing question rather than a query problem. Contact support or update the billing details, as the message says.

Check SDK behavior​

  • These examples use JavaScript SDK 1.5.3 and Python SDK 0.2.1.
  • The two SDKs take parameters differently. JavaScript wraps them in an options object, analytics.execute('SLUG', {params: {...}}); Python takes them directly, client.analytics.execute("SLUG", params={...}). Check this first if you adapted a call from the other language's tab.
  • Both SDKs cover execution only. Create, edit, save, and delete queries in TaruviBase Console.
  • Neither SDK unwraps the response for you — read the rows from data on the returned object rather than expecting the rows directly.
  • Compare an SDK call with a Run from the query's page in Console. Console counts the rows it received and doesn't show the execution key, so expect those two differences; see the execution response format.

Prepare a support request​

Include:

  • the execution key returned with the failed run;
  • the query slug and the app that owns it;
  • the connection mode, and the connection secret key for an external query;
  • the parameter names you supplied, without their values if any are sensitive; and
  • the error category and a summary of the message with any sensitive details removed.

Keep the report safe by leaving out credentials, parameter values, personal data, and infrastructure details. Raw caller parameters and final error text are persisted with the execution.