OtterMind/Chat2DB · error · BusinessException

mysql.account.grantsUnavailable

mysql.account.grantsUnavailable

Error message

mysql.account.grantsUnavailable

What it means

Thrown by MysqlAccountManager.showGrants when the underlying 'SHOW GRANTS' query fails. The SQLException is wrapped in BusinessException('mysql.account.grantsUnavailable') so the caller receives a localized message while the original SQL error is preserved as the cause. It fires when the user cannot run SHOW GRANTS for the requested account.

Solutions

  1. Connect with an account that has rights to inspect other users' grants (e.g. SELECT on mysql or a DBA role).
  2. Confirm the user/host pair corresponds to an existing account (listAccounts first).
  3. Inspect BusinessException.getCause() for the SQLException to distinguish 'no such account' from a privilege denial.
  4. Handle the empty/failed result gracefully in the UI rather than crashing the grants panel.

Example fix

// before
List<String> grants = accountManager.showGrants(connection, user, host);

// after
List<String> grants;
try {
    grants = accountManager.showGrants(connection, user, host);
} catch (BusinessException e) {
    if ("mysql.account.grantsUnavailable".equals(e.getCode())) {
        log.warn("Cannot load grants for {}@{}: {}", user, host, rootMessage(e.getCause()));
        grants = Collections.emptyList();
    } else {
        throw e;
    }
}
Defensive patterns

Strategy: try-catch

Validate before calling

// Confirm the account exists and the user can inspect grants before calling.
if (!accountExists(connection, user, host)) {
    return Collections.emptyList();
}

Try / catch

try {
    return accountManager.showGrants(connection, user, host);
} catch (BusinessException e) {
    if ("mysql.account.grantsUnavailable".equals(e.getCode())) {
        log.warn("grants unavailable for {}@{}: {}", user, host, rootMessage(e.getCause()));
        return Collections.emptyList();
    }
    throw e;
}

Prevention

When it happens

Trigger: showGrants(connection, user, host) where queryGrants throws: the connected user lacks privilege to view grants for the target account (SHOW GRANTS requires viewing your own grants unless you have SELECT on mysql or broader rights), the user/host arguments are malformed, or the connection dropped.

Common situations: An admin viewing another user's grants while connected as a non-privileged account; passing a host of '%' that does not match any row; a connection that lost its session; SHOW GRANTS FOR with a non-existent account returns an error.

Related errors


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

Appendix: source

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

    @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());
        preview.setSql(MysqlAccountSqlBuilder.buildDisplaySql(command));
        preview.setPreviewToken(MysqlAccountSqlBuilder.previewToken(sql));
        return preview;
    }

    @Override
    public AccountExecuteResponse execute(Connection connection, AccountOperationRequest command) {
        AccountPreview preview = preview(command);
        if (!StringUtils.equals(preview.getPreviewToken(), command.getPreviewToken())) {
            throw new BusinessException(ERROR_KEY_ACCOUNT_PREVIEW_TOKEN_MISMATCH);

View on GitHub (pinned to 5ee1e990e7)