Error messages, decoded

What does the SuiteQL error 'Invalid or unsupported search' mean?

Updated
suiteqlerrorscastdatesgrouping-setsjoins

Short answer

A generic refusal carrying no error code, no position and no identifier name. In this run it came from CAST(id AS VARCHAR(20)), a date column compared to a bare ISO string, GROUPING SETS, and one RIGHT JOIN.

It is a refusal, not a diagnosis. The string carries no error code, no character offset and no identifier name, so it does not tell you which part of the statement it objected to. Bisect the statement and swap the refused construct for one the engine accepts.

Minimal reproduction

SELECT CAST(id AS VARCHAR(20)) AS s FROM transaction FETCH FIRST 3 ROWS ONLY
N/query.runSuiteQL error: Search error occurred: Invalid or unsupported search

That is the whole error.

Which error family you are in

Three generic-looking strings come out of this engine and they are not interchangeable.

String What it looks like
Search error occurred: Invalid or unsupported search The bare sentence above. No code, no position, no name.
Unexpected Error Even barer. No code, no position, no name, and note it arrives with no Search error occurred: wrapper at all.
Failed to parse SQL [...]: syntax error, state:0(10102) near: FETCH(1,44, token code:0) Echoes your statement and points at a token.

The third one is the trap. An unresolvable column is the most common cause of syntax error ... near: FETCH(1,NN, token code:0), but it is not the only thing an unresolvable column can produce: the same shape, a column that does not exist on the table plus a FETCH FIRST clause, returned a bare Unexpected Error. So the rule to follow is the action, not the diagnosis: if SuiteQL blames your FETCH clause, delete the FETCH clause and run again, because the second error names the real problem.

The four constructs that produced it, and what the run tested in their place

Refused What the run tested in its place
CAST(id AS VARCHAR(20)) No substitute. TO_CHAR on a date column, TO_NUMBER('42') and TO_DATE('2026-01-15','YYYY-MM-DD') all run, but none of them converts a number to a string, and TO_CHAR on a numeric column was not tested.
WHERE trandate >= '2026-01-01', a bare ISO string TO_DATE('2026-01-01','YYYY-MM-DD'), DATE '2026-01-01' and '1/1/2026' in the account's own display format all run, and all three returned the identical count.
GROUP BY GROUPING SETS ((type), (status)) GROUP BY ROLLUP(type) runs, and its null-marker superaggregate row is the true grand total.
transaction t RIGHT JOIN transactionAccountingLine tal ON 1 = 0 No outer join to transactionAccountingLine succeeded. The only join to that table the run got working is the inner compound-key form, ON tl.transaction = tal.transaction AND tl.id = tal.transactionline.

TO_CHAR with an explicit format mask does run, on a date column:

SELECT TO_CHAR(trandate, 'YYYY-MM-DD') AS d FROM transaction FETCH FIRST 3 ROWS ONLY

It returns the value as a string rendered exactly per the mask, with no time component. That is a date going in. The numeric case, which is what CAST(id AS VARCHAR(20)) was doing, was not tested at all, so test it in your own account before relying on it.

Why this happens

Four unrelated constructs return the identical string, which is what makes it a catch-all rather than a diagnosis. The distinction from the parse errors is directly observed: those name a state, a token and an offset, and this one is a bare sentence.

Beyond that it is inference. Nothing in the run establishes which execution stage raises it. For GROUPING SETS specifically, the attribution rests on ROLLUP succeeding in an otherwise similar statement, not on the error text, which names nothing.

Do not read the string as "the search is invalid". None of these four cases involved a saved search.

How to tell if you are affected

This error is loud, so the risk is not missing it. The risk is its neighbour that fails silently. The RIGHT JOIN above is refused outright when the right side is transactionAccountingLine, but the same join against transactionLine returns a plausible wrong number instead of an error. Run these two statements separately:

SELECT COUNT(*) AS n FROM transaction t RIGHT JOIN transactionLine tl ON 1 = 0
SELECT COUNT(*) AS n FROM transactionLine

ON 1 = 0 matches nothing, so a working RIGHT JOIN has to null-supply every line row and the first statement must return exactly the second statement's count. If instead the first returns zero, the join ran as an inner join, and every orphan hunt you have run against that pair has been answering "none found" for the wrong reason. Here the first returned zero. Full details are on the RIGHT JOIN page.

Scope: one production account on NetSuite 2026.1, entirely through N/query.runSuiteQL. This finding was not tested on the REST endpoint. The error strings above are NetSuite's text verbatim.

Not every statement named on this page is a failure. Four of them produced this error: the CAST to VARCHAR, the date column compared to a bare ISO string, the GROUPING SETS clause, and the RIGHT JOIN to transactionAccountingLine. The rest are controls that succeeded: TO_CHAR on a date column, TO_NUMBER, TO_DATE, the DATE literal, the display-format date string, ROLLUP, and the inner compound-key join to transactionAccountingLine. The unresolvable-column statements are mentioned only for the error-family comparison above. These four triggers are the ones seen in one run, not the full list.

How this was established

14 probe runs against one live NetSuite 2026.1 account on the Administrator role, through N/query.runSuiteQL. Where this page draws a boundary around a finding, that boundary is the edge of what was actually run.

Related