iflytek/astron-agent · error · BusinessException
8515
8515
Error message
database.table.delete.failed
What it means
Thrown by DatabaseService.deleteTable when any unexpected exception occurs while deleting a table record and its field rows (the generic catch-all after BusinessException is rethrown). Code 8515, message 'database.table.delete.failed'. It wraps root causes like SQL errors, mapper failures, or constraint violations during the delete transaction.
Solutions
- Check the server log for 'Failed to delete table, tbId=...' to find the root-cause stack trace from the wrapped exception.
- Verify database connectivity and credentials (datasource health, connection pool exhaustion).
- Confirm the tbId exists and is not locked by a concurrent transaction; retry after the lock clears.
- Check for foreign-key constraints referencing the table rows that block the delete.
- Re-run the delete after fixing the root cause; if permission-related, a different BusinessException is raised instead.
Example fix
// before: only generic handling
try {
removeTable(tbId);
} catch (Exception ex) {
throw new BusinessException(ResponseEnum.DATABASE_TABLE_DELETE_FAILED);
}
// after: distinguish and surface root cause
try {
removeTable(tbId);
} catch (BusinessException ex) {
throw ex;
} catch (DuplicateKeyException | DataIntegrityViolationException ex) {
log.error("Table rows still referenced, tbId={}", tbId, ex);
throw new BusinessException(ResponseEnum.DATABASE_TABLE_DELETE_FAILED);
} Defensive patterns
Strategy: try-catch
Validate before calling
Long count = dbTableMapper.selectCount(new LambdaQueryWrapper<DbTable>().eq(DbTable::getTbId, tbId));
if (count == 0) throw new IllegalStateException("table does not exist: " + tbId); Try / catch
try {
databaseService.deleteTable(tbId);
} catch (BusinessException ex) {
if ("database.table.delete.failed".equals(ex.getMessage())) {
log.error("delete failed for tbId={}, root cause in server log", tbId, ex);
}
throw ex;
} Prevention
- Check DB connectivity/health before batch delete operations
- Confirm tbId exists and no dependent rows reference it
- Retry transient failures with backoff
When it happens
Trigger: Calling deleteTable(tbId) when the underlying DELETE via dbTableFieldMapper/dbTable mapper fails — e.g. DB connection failure, SQL syntax error, foreign-key constraint, or the row was concurrently deleted. BusinessException from permission checks is rethrown unchanged, so this error only appears for non-business exceptions.
Common situations: Database unreachable or credentials rotated; table row locked by a concurrent transaction; schema drift between the entity mapping and actual DB schema; disk full on the DB host.
Related errors
AI-assisted analysis of iflytek/astron-agent@5e758547a8 (2026-09-12).
Data as JSON: /api/errors/256a68a87ac54978.
Report an issue: GitHub.
Appendix: source
Thrown at console/backend/toolkit/src/main/java/com/iflytek/astron/console/toolkit/service/database/DatabaseService.java:665
dbTableDto.setName(dbTable.getName());
String ddl = buildDDL(dbTableDto, DBOperateEnum.DELETE.getCode(), null);
// Delete from core system
for (String stmt : safeSplitStatements(ddl)) {
SqlRenderer.denyMultiStmtOrComment(stmt); // At this point each statement does not contain semicolon
coreSystemService.execDDL(stmt, UserInfoManagerHandler.getUserId(), SpaceInfoUtil.getSpaceId(), dbInfo.getDbId());
}
dbTableMapper.update(new UpdateWrapper<DbTable>().lambda()
.eq(DbTable::getId, tbId)
.set(DbTable::getDeleted, true));
// Delete table fields
dbTableFieldMapper.delete(new UpdateWrapper<DbTableField>().lambda()
.eq(DbTableField::getTbId, tbId));
} catch (BusinessException ex) {
log.error("Failed to delete table, tbId={}", tbId);
throw ex;
} catch (Exception ex) {
log.error("Failed to delete table, tbId={}", tbId, ex);
throw new BusinessException(ResponseEnum.DATABASE_TABLE_DELETE_FAILED);
}
}
public void operateTableData(DbTableOperateDto dbTableOperateDto) {
dataPermissionCheckTool.checkTbBelong(dbTableOperateDto.getTbId());
try {
DbTable dbTable = dbTableMapper.selectById(dbTableOperateDto.getTbId());
List<DbTableField> fields = dbTableFieldMapper.selectList(new QueryWrapper<DbTableField>().lambda()
.eq(DbTableField::getTbId, dbTable.getId()));
DbInfo dbInfo = dbInfoMapper.selectById(dbTable.getDbId());
// Validate and execute one by one (can be batched to improve availability)
final int BATCH = 100; // Adjustable
List<DbTableDataDto> rows = dbTableOperateDto.getData();
for (int i = 0; i < rows.size(); i++) {
DbTableDataDto data = rows.get(i);
validateParams(data.getTableData(), fields, data.getOperateType());
View on GitHub (pinned to 5e758547a8)