prestodb/presto · error · PrestoException
NOT_FOUND
NOT_FOUND
Error message
Branch '%s' does not exist in table %S
What it means
Thrown by resolveSnapshotIdByName when a table name references a branch (e.g. 'table@branch' syntax) that is not an existing branch ref in the Iceberg table metadata. The code checks table.refs() for the name and whether it is actually a branch; if not found or not a branch, it throws NOT_FOUND. This ensures branch-based reads/writes target a real Iceberg branch.
Source
Thrown at presto-iceberg/src/main/java/com/facebook/presto/iceberg/IcebergUtil.java:397
.collect(toImmutableList());
}
public static Optional<Long> resolveSnapshotIdByName(Table table, IcebergTableName name)
{
if (name.getSnapshotId().isPresent()) {
if (table.snapshot(name.getSnapshotId().get()) == null) {
throw new PrestoException(ICEBERG_INVALID_SNAPSHOT_ID, format("Invalid snapshot [%s] for table: %s", name.getSnapshotId().get(), table));
}
return name.getSnapshotId();
}
if (name.getBranchName().isPresent()) {
String branchName = name.getBranchName().get();
SnapshotRef branchRef = table.refs().get(branchName);
if (branchRef != null && branchRef.isBranch()) {
return Optional.of(branchRef.snapshotId());
}
throw new PrestoException(NOT_FOUND, format("Branch '%s' does not exist in table %S", branchName, table));
}
if (name.getTableType() == IcebergTableType.CHANGELOG) {
return Optional.ofNullable(SnapshotUtil.oldestAncestor(table)).map(Snapshot::snapshotId);
}
return tryGetCurrentSnapshot(table).map(Snapshot::snapshotId);
}
public static long getSnapshotIdTimeOperator(Table table, long millisUtc, VersionOperator operator)
{
return table.history().stream()
.filter(logEntry -> operator == VersionOperator.EQUAL ? logEntry.timestampMillis() <= millisUtc : logEntry.timestampMillis() < millisUtc)
.max(comparing(HistoryEntry::timestampMillis))
.orElseThrow(() -> new PrestoException(ICEBERG_INVALID_TABLE_TIMESTAMP, format("No history found based on timestamp for table %s", table.name())))
.snapshotId();
}
View on GitHub (pinned to 55bb57d202)
Solutions
- Verify the branch exists: SELECT name FROM "catalog.db.t$refs" WHERE type = 'BRANCH'
- Create the missing branch with ALTER TABLE ... CREATE BRANCH (or ALTER TABLE ... CREATE BRANCH AS OF the desired snapshot)
- Fix the branch-name typo or case in the query
- If the ref is a tag, use tag syntax (FOR VERSION AS OF tag) instead of branch syntax
Example fix
// before SELECT * FROM catalog.db.t@audit_branch; -- branch never created // after ALTER TABLE catalog.db.t CREATE BRANCH audit_branch; SELECT * FROM catalog.db.t@audit_branch;
Defensive patterns
Strategy: validation
Validate before calling
// Check refs before using branch syntax
boolean ok = table.refs().containsKey(branchName)
&& table.refs().get(branchName).isBranch();
if (!ok) throw new IllegalArgumentException("Not a branch: " + branchName); Type guard
boolean isBranch(Table table, String name) {
SnapshotRef ref = table.refs().get(name);
return ref != null && ref.isBranch();
} Try / catch
try {
return resolveSnapshotIdByName(table, name);
} catch (PrestoException e) {
if (e.getErrorCode() == StandardErrorCode.NOT_FOUND) {
throw new UserError("Branch not found; valid branches: " + table.refs().keySet());
}
throw e;
} Prevention
- List refs via "table$refs" and filter type = 'BRANCH' before branch queries
- Use CREATE BRANCH before referencing a new branch in SQL
- Remember tags are not branches — use the right syntax for each ref kind
- Watch case sensitivity: branch names are matched exactly (the message prints %S uppercase, which can mislead)
When it happens
Trigger: Calling resolveSnapshotIdByName with an IcebergTableName carrying a branchName that either does not exist in table.refs(), or exists as a non-branch ref (e.g. a tag). Note the format string uses %S so the branch name is printed uppercase in the message.
Common situations: Typo in the branch name in the SQL (table@maim instead of @main); referencing a branch that was deleted or never created (CREATE BRANCH not run); accidentally using a tag name where a branch is expected; case-sensitivity mismatch between SQL and the created branch name.
Understand the failure class
Background: NOT_FOUND error code: why tRPC, Harbor, Nacos and other libraries return 404 "not found" errors for resources that may still exist — this error's family across 11 libraries.
Related errors
AI-assisted analysis of prestodb/presto@55bb57d202 (2026-09-04).
Data as JSON: /api/errors/e6ff46c2e6ff12f9.
Report an issue: GitHub.