hs-web/hsweb-framework · error · IllegalStateException
table " + table.getName() + " not found in join
Error message
table " + table.getName() + " not found in join
What it means
During column visiting, the analyzer maps a column's table alias to a previously registered join via `joins.get(alias)`. When an alias referenced in the SELECT list was never registered by a JOIN clause, the lookup returns null and an IllegalStateException is thrown, indicating the query references a table that is not part of the FROM/JOIN structure the analyzer built.
Solutions
- Ensure every alias used to qualify columns has a corresponding `JOIN table alias` clause in the query.
- Remove or correct the stale alias in the SELECT list.
- Check alias quoting: use the same spelling (no extra quotes/backticks) in the JOIN and in column qualifiers.
Example fix
// before "select t2.name from user t1" // after "select t2.name from user t1 join role t2 on t1.id = t2.user_id"
Defensive patterns
Strategy: validation
Validate before calling
Set<String> aliases = extractJoinAliases(sql); for (String q : extractColumnQualifiers(sql)) { if (!aliases.contains(q) && !q.equals(fromAlias)) { throw new IllegalArgumentException("unknown alias: " + q); } } Try / catch
try { analyzer.analyze(dql); } catch (IllegalStateException e) { if (e.getMessage().contains("not found in join")) { log.warn("stale alias in query: {}", e.getMessage()); } throw e; } Prevention
- Keep SELECT qualifiers in sync with JOIN clauses
- Search codebase for removed joins after refactoring SQL
- Use the same alias spelling everywhere (no mixed quoting)
When it happens
Trigger: Running an analyzed query whose SELECT list qualifies a column with an alias (`t1.name`) that appears neither in FROM nor in any JOIN clause, or where the join alias differs (case/`parsePlainName` stripping) from the qualifier used.
Common situations: Copy-pasted SQL with leftover aliases after removing a JOIN; dynamically assembled query builders emitting stale aliases; aliases created via quoted or backtick-quoted identifiers that parsePlainName strips differently.
Understand the failure class
Background: 'Could not be found', 'does not exist', 'not found in database': the resource-not-found family when an ID, slug, key, or URI lookup comes back empty — this error's family across 20 libraries.
Related errors
- table " + table + " not found in from or join
- table or view " + tableName.getName() + " not found in " +…
- table function[" + tableFunction + "] must have alias
- column [" + column.getColumnName() + "] not found in " +…
- select can not be without 'from'
AI-assisted analysis of hs-web/hsweb-framework@b2cfc85a57 (2026-09-13).
Data as JSON: /api/errors/d180792350f81598.
Report an issue: GitHub.
Appendix: source
Thrown at hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/query/QueryAnalyzerImpl.java:464
}
}
}
@Override
public void visit(AllTableColumns allTableColumns) {
net.sf.jsqlparser.schema.Table table = allTableColumns.getTable();
String name = table.getName();
if (Objects.equals(select.table.alias, name)) {
putSelectColumns(select.table, select.columnList);
return;
}
QueryAnalyzer.Join join = joins.get(parsePlainName(table.getName()));
if (join == null) {
throw new IllegalStateException("table " + table.getName() + " not found in join");
}
putSelectColumns(join.table, select.columnList);
}
private QueryAnalyzer.Table getTable(net.sf.jsqlparser.schema.Table table) {
QueryAnalyzer.Table meta;
if (null == table) {
return select.table;
}
String tableName = parsePlainName(table.getName());
if (Objects.equals(tableName, select.table.alias)) {
meta = select.table;
} else {
QueryAnalyzer.Join join = joins.get(tableName);
if (join == null) {
throw new IllegalStateException("table " + table + " not found in from or join");
}View on GitHub (pinned to b2cfc85a57)