nocobase/nocobase · error

Only select query allowed

Error message

Only select query allowed

What it means

The charts query runner whitelists read-only statements: SQL must start with SELECT or be a WITH ... SELECT CTE. Anything else (UPDATE, DELETE, INSERT, DROP, etc.) is rejected to prevent the charting feature from mutating data.

Source

Thrown at packages/plugins/@nocobase/plugin-charts/src/server/query.ts:35

    return options.data || [];
  },
  sql: async (
    options,
    {
      db,
      transaction,
      skipError,
      validateSQL,
    }: { db: Database; transaction?: any; skipError?: boolean; validateSQL?: boolean },
  ) => {
    try {
      // 分号截取,只取第一段
      const sql: string = options.sql.trim().split(';').shift();
      if (!sql) {
        throw new Error('SQL is empty');
      }
      if (!/^select/i.test(sql) && !/^with([\s\S]+)select([\s\S]+)/i.test(sql)) {
        throw new Error('Only select query allowed');
      }
      const [data] = await db.sequelize.query(sql, { transaction });
      return data;
    } catch (error) {
      if (skipError) {
        return [];
      }
      throw error;
    }
  },
};

export default query;

View on GitHub (pinned to fa42722fef)

Solutions

  1. Rewrite the query to return data with SELECT (or WITH ... SELECT)
  2. Move any write/maintenance logic out of chart queries into server code or migrations
  3. If aggregates are needed, wrap the logic in a DB view and SELECT from it

Example fix

// before
const sql = "UPDATE charts SET x = 1";
// after
const sql = "SELECT id, x FROM charts";
Defensive patterns

Strategy: validation

Validate before calling

const first = sql.trim().split(';')[0];
if (!/^select/i.test(first) && !/^with[\s\S]+select[\s\S]+/i.test(first)) {
  throw new Error('Chart SQL must be a SELECT or WITH...SELECT statement');
}

Type guard

function isReadOnlySql(sql: string): boolean {
  const s = sql.trim().split(';')[0];
  return /^select/i.test(s) || /^with[\s\S]+select[\s\S]+/i.test(s);
}

Try / catch

try {
  const data = await query(sql);
} catch (e) {
  if (e.message === 'Only select query allowed') {
    message.error('Only SELECT queries are allowed in charts');
    return [];
  }
  throw e;
}

Prevention

When it happens

Trigger: A chart query configured with a non-select statement, or SQL whose first statement is not SELECT/WITH (note the regex only inspects the first semicolon-delimited statement).

Common situations: Developers pasting maintenance SQL into charts; building charts on stored procedures or DML; trying to run EXPLAIN-style or multi-statement scripts through the chart UI.

Related errors


AI-assisted analysis of nocobase/nocobase@fa42722fef (2026-09-01). Data as JSON: /api/errors/cdb1f852befdb1d1. Report an issue: GitHub.