Error messages, decoded
What does SuiteQL mean by Unknown identifier 'x'. Available identifiers are: {transaction=transaction}?
Short answer
The column does not exist on that table. Despite the wording, "Available identifiers" lists the table aliases in scope, not the columns you could have used. Adding a FETCH FIRST clause can hide this error behind a syntax error.
The column does not exist on that table. Available identifiers lists the table aliases in scope, not the columns you could have used, so it is not a hint about what to type instead.
Minimal reproduction
SELECT id, CASE WHEN foreignamount > 0 THEN 'positive' ELSE 'other' END AS bucket FROM transaction
N/query.runSuiteQL error: Search error occurred: Unknown identifier 'foreignamount'. Available identifiers are: {transaction=transaction}
The braced fragment mirrors the FROM clause. A different query against employee returned Unknown identifier 'timezone'. Available identifiers are: {employee=employee} in the same shape, which is what shows that the content is the alias map and not a column list.
The fix
Find the table the column actually lives on, then query it there.
SELECT foreignamount FROM transactionLine FETCH FIRST 1 ROWS ONLY
That returns a row. foreignamount is a transactionLine column and does not exist on transaction, even though transaction in the same account does carry foreignamountpaid and foreignamountunpaid. The header and line split is not derivable from the names.
To see the column list for any table, ask for one row of everything:
SELECT * FROM transactionAccountingLine FETCH FIRST 1 ROWS ONLY
Columns whose value is null on that row still come back as explicit JSON keys with a null value rather than being omitted, so a null-heavy sample row does not shorten the list you get back.
Why this happens
The message is produced by name resolution, not by the parser: the statement text is not echoed, there is no offset and no token code, unlike the Failed to parse SQL [...] family. The alias map is the resolver reporting what scope it searched.
Nothing here proves the resolver has no access to a column list, only that it does not print one. The wording is unhelpful; that is an observation about the string, not about NetSuite internals.
The practical detail is that you often do not get this error at all. Append FETCH FIRST 5 ROWS ONLY to the statement above and the same unresolvable column reports syntax error, state:0(10102) near: FETCH instead, pointing at a clause that is perfectly valid. That is the usual outcome, and since almost everyone writes a row limit while exploring, the honest error is the one you rarely see. It is not the only substitute either: SELECT tal.subsidiary FROM transactionAccountingLine tal FETCH FIRST 1 ROWS ONLY names a column that is not on that table and returns a bare Unexpected Error.
So the rule to keep 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.
How to tell if you are affected
You are looking at the useful error already. To confirm which table owns the column, run one row of everything against each candidate table and search the key set for the name:
SELECT * FROM transaction FETCH FIRST 1 ROWS ONLY
SELECT * FROM transactionLine FETCH FIRST 1 ROWS ONLY
If the name is absent from the table you were querying and present on the other, that is your bug and the fix is to move the reference. If the name is present on the table you were querying, the column is not what the error is about and you should re-read the quoted identifier in the message, which may be an alias or a second column you forgot about.
Custom fields appear inline in that output with no special syntax, so the same test covers custbody_* and custcol_* columns. A custom body field found that way was then queryable directly by its field id off transaction, with no join and no separate catalog lookup.
Scope: one production account on NetSuite 2026.1. Every probe behind this page ran entirely through N/query.runSuiteQL; the finding was not tested on the REST endpoint. Everything from N/query.runSuiteQL error: onward is NetSuite's own text; that prefix is added by the N/query module. Which columns sit on which table is partly account-specific, so use the test rather than the example.
How this was established
8 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
- 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.
- How do I list the tables and columns in a NetSuite account from SuiteQL?
You cannot. OA_TABLES and OA_COLUMNS are rejected with "Invalid search type", and ALL_TABLES, USER_TAB_COLUMNS and ALL_TAB_COLUMNS are absent too. For columns, run SELECT * with FETCH FIRST 1 ROWS ONLY; for custom records, query customrecordtype.
- What does 'N/query.runSuiteQL error: Unexpected Error' mean in SuiteQL?
It carries no code, no position and no identifier name. Read it as "something here is unsupported" and bisect the query. In this run it came from three BUILTIN calls and from a column that does not exist.
From the blog
- NetSuite Field Explorer vs MokuBot: Two Different Questions
Field Explorer tells you what a field is called. MokuBot uses the field. An honest comparison of the two, including where Field Explorer is still the better tool.