Row limits and pagination
Why does LIMIT 5 not work in SuiteQL, and what should I use instead?
Short answer
LIMIT is not in the SuiteQL dialect. Both engines reject it with a parse error pointing at the number after it. Use FETCH FIRST 5 ROWS ONLY; WHERE ROWNUM <= 5 and SELECT TOP 5 also worked.
LIMIT is not part of the SuiteQL dialect and is rejected before the query runs. Use FETCH FIRST 5 ROWS ONLY. WHERE ROWNUM <= 5 and SELECT TOP 5 also work and returned identical rows.
Minimal reproduction
SELECT id FROM transaction LIMIT 5
Through N/query.runSuiteQL, verbatim:
N/query.runSuiteQL error: Search error occurred: Failed to parse SQL [SELECT id FROM transaction LIMIT 5]: syntax error, state:961(10102) near: 5(1,34, token code:0)
The same statement through POST /services/rest/query/v1/suiteql returns HTTP 400, error code INVALID_PARAMETER, with this detail:
Invalid search query. Detailed unprocessed description follows. Search error occurred: Failed to parse SQL [SELECT id FROM transaction LIMIT 5]: syntax error, state:961(10102) near: 5(1,34, token code:0)
no_root_node(-1000) near: no root node(0,0, token code:0).
The fix
Any of these three. Each is one statement; SuiteQL takes one statement per call.
SELECT id FROM transaction FETCH FIRST 5 ROWS ONLY
SELECT id FROM transaction WHERE ROWNUM <= 5
SELECT TOP 5 id FROM transaction
All three ran on the same table in the same session and returned the same five ids in the same order.
None of the three carried an ORDER BY, so the rows they agree on are a prefix of the engine's internal scan order, which is not a defined ordering. Add ORDER BY if you care which five rows you get. Prefer the FETCH form: it is the only row limiter this run combined with ORDER BY (ORDER BY id ... FETCH NEXT 10 ROWS ONLY). ORDER BY with ROWNUM or with TOP was not tested here, so this page says nothing about how those two behave once an ordering is added.
Why this happens
The parser offset is the tell. In SELECT id FROM transaction LIMIT 5 position 34 is the digit 5, and the keyword LIMIT starts at position 28. The keyword itself is consumed without complaint and the statement only falls over on the number after it. The most likely reading is that LIMIT is being taken as a table alias for transaction, which leaves a bare literal where the parser expects a clause. That last step is inference; what the probes establish is the offset.
SELECT TOP 5 deserves a flag of its own. TOP is T-SQL, not Oracle syntax, and it is commonly assumed that SuiteQL accepts only the Oracle row-limiting forms. It parsed and executed without error on both engines.
If the error blames your FETCH clause instead
Once you switch to FETCH FIRST, a different error becomes possible: syntax error, state:0(10102) near: FETCH(1,NN, token code:0), pointing at a FETCH clause that is perfectly valid.
An unresolvable column is the most common cause of that error. It is not the only thing an unresolvable column can produce: the same shape, a column that does not exist on the table plus FETCH FIRST 1 ROWS ONLY, returned a bare Unexpected Error in one run. 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. Put the clause back afterwards.
How to tell if you are affected
Two statements, run separately. Branch on whether each one errors, not on how many rows it returns, so that an empty table does not confuse the reading.
SELECT id FROM transaction LIMIT 5
SELECT TOP 5 id FROM transaction
If the first fails to parse with an error naming the position of the digit, and the second runs without error, your engine behaves like the one probed here and you have three working row limiters, not one. If the first returns rows, your engine accepts LIMIT and this page does not apply to it. If the second errors, TOP is not available to you; fall back to FETCH FIRST 5 ROWS ONLY.
Scope: one production account on NetSuite 2026.1, Administrator role. LIMIT and TOP were run on both N/query.runSuiteQL and the REST endpoint. WHERE ROWNUM was run only through N/query.runSuiteQL and was not tested on the REST endpoint. FETCH FIRST ran without error on both, though its REST outing comes from an unrelated aliasing test rather than from a row-limit test.
How this was established
10 probe runs against one live NetSuite 2026.1 account on the Administrator role, through N/query.runSuiteQL and cross-checked against the REST query endpoint. Where this page draws a boundary around a finding, that boundary is the edge of what was actually run.
Related
- SuiteQL says syntax error near FETCH, but my FETCH FIRST clause is fine. What is wrong?
Your FETCH clause is probably fine. A column that does not exist on the table is the usual cause. Delete the FETCH FIRST clause, run the statement again, and the second error names the real problem.
- Why does SuiteQL OFFSET return the same rows as page 1?
The SQL clause OFFSET n ROWS FETCH NEXT m ROWS ONLY has its OFFSET silently discarded on both engines, even with an explicit ORDER BY. Every page returns the first rows again. Paginate with the REST ?offset= parameter instead.
- Why does CONNECT BY fail in SuiteQL with no_root_node?
START WITH CONNECT BY PRIOR fails at parse time here: a syntax error at the column inside START WITH, plus no_root_node. The statement does not reach execution, so LEVEL and SYS_CONNECT_BY_PATH stay untested. Build the tree yourself.
From the blog
- SuiteScript Governance: Why Your Script Works in Sandbox and Dies in Production
Governance units are a per-execution budget, not a rate limit. The arithmetic that decides whether your SuiteScript survives, and the four substitutions that buy back the most headroom.