OtterMind/Chat2DB · error · BusinessException

mysql.account.listUnavailable

mysql.account.listUnavailable

Error message

mysql.account.listUnavailable

What it means

Thrown by MysqlAccountManager.listAccounts after both attempts to read the mysql.user table fail. The method first tries a query including the account_locked column; on failure it retries without that column; if that also throws SQLException it wraps the cause in BusinessException('mysql.account.listUnavailable'). It signals the connected user cannot enumerate accounts at all.

Source

Thrown at chat2db-community-server/chat2db-community-plugins/chat2db-community-mysql/src/main/java/ai/chat2db/plugin/mysql/account/MysqlAccountManager.java:51

            DatabaseMetaData metaData = connection.getMetaData();
            capability.setProductName(metaData.getDatabaseProductName());
            capability.setProductVersion(metaData.getDatabaseProductVersion());
        } catch (SQLException e) {
            capability.setMessage(e.getMessage());
        }
        capability.setCurrentUser(querySingleString(connection, SQL_SELECT_CURRENT_USER));
        return capability;
    }

    @Override
    public List<AccountInfo> listAccounts(Connection connection) {
        try {
            return queryAccounts(connection, true);
        } catch (SQLException lockedColumnError) {
            try {
                return queryAccounts(connection, false);
            } catch (SQLException e) {
                throw new BusinessException(ERROR_KEY_ACCOUNT_LIST_UNAVAILABLE, null, e);
            }
        }
    }

    @Override
    public List<String> showGrants(Connection connection, String user, String host) {
        try {
            return queryGrants(connection, user, host);
        } catch (SQLException e) {
            throw new BusinessException(ERROR_KEY_ACCOUNT_GRANTS_UNAVAILABLE, null, e);
        }
    }

    @Override
    public AccountPreview preview(AccountOperationRequest command) {
        String sql = MysqlAccountSqlBuilder.buildSql(command);
        AccountPreview preview = new AccountPreview();
        preview.setActionType(command.getActionType());

View on GitHub (pinned to 5ee1e990e7)

Solutions

  1. Grant the connected user SELECT on mysql.user (or a broader account-read privilege appropriate to the deployment).
  2. Inspect BusinessException.getCause() for the SQLException's SQL state/error code to pinpoint the denial.
  3. Verify the datasource is genuine MySQL and the columns match the expected schema.
  4. If the user must remain restricted, disable the account-listing feature for that connection and degrade gracefully.

Example fix

// before
List<AccountInfo> accounts = accountManager.listAccounts(connection);

// after
List<AccountInfo> accounts;
try {
    accounts = accountManager.listAccounts(connection);
} catch (BusinessException e) {
    if ("mysql.account.listUnavailable".equals(e.getCode())) {
        log.warn("Cannot list accounts: {}", rootMessage(e.getCause()));
        accounts = Collections.emptyList();
    } else {
        throw e;
    }
}
Defensive patterns

Strategy: try-catch

Validate before calling

// Ensure the connected user can read mysql.user before enabling account listing.
if (!accountManager.capability(connection).isAccountListReadable()) {
    return Collections.emptyList();
}

Try / catch

try {
    return accountManager.listAccounts(connection);
} catch (BusinessException e) {
    if ("mysql.account.listUnavailable".equals(e.getCode())) {
        log.warn("account list unavailable: {}", rootMessage(e.getCause()));
        return Collections.emptyList();
    }
    throw e;
}

Prevention

When it happens

Trigger: listAccounts(connection) where queryAccounts fails both with and without the locked column: the connected user lacks SELECT on mysql.user, the server is a MySQL fork without the expected columns, the connection was dropped, or a non-MySQL server is mistakenly treated as MySQL.

Common situations: Connecting with a restricted application user that has no access to mysql.user; Aurora/RDS privilege restrictions; a proxy or connection-pool reset mid-query; an older MySQL (5.6) lacking the account_locked column combined with a second unrelated failure.

Related errors


AI-assisted analysis of OtterMind/Chat2DB@5ee1e990e7 (2026-08-14). Data as JSON: /api/errors/10c3445e9d48120b. Report an issue: GitHub.