remix-run/remix · error · DataTableQueryError

Unknown query execution mode

Error message

Unknown query execution mode

What it means

executeQuery dispatches on the query plan's execution mode with a switch statement; this error is the default branch. It means the plan contained an operation string the current version of the library does not recognize, which can only happen if plans are serialized/cached across versions or constructed manually. It is effectively an internal invariant violation rather than a user input error.

Source

Thrown at packages/data-table/src/lib/database/query-execution.ts:119

        snapshot.plan.changes as Record<string, unknown>,
        snapshot.plan.options,
      )) as QueryExecutionResult<input>
    case 'delete':
      return (await executeDelete(
        database,
        snapshot.table,
        snapshot.state,
        snapshot.plan.options,
      )) as QueryExecutionResult<input>
    case 'upsert':
      return (await executeUpsert(
        database,
        snapshot.table,
        snapshot.plan.values as Record<string, unknown>,
        snapshot.plan.options,
      )) as QueryExecutionResult<input>
    default:
      throw new DataTableQueryError('Unknown query execution mode')
  }
}

export async function loadRowsWithRelationsForQuery(
  database: QueryExecutionContext,
  input: AnyQuery,
): Promise<Record<string, unknown>[]> {
  let snapshot = input[querySnapshot]()
  return loadRowsWithRelationsForState(database, snapshot.table, snapshot.state)
}

export async function loadRowsWithRelationsForState(
  database: QueryExecutionContext,
  table: AnyTable,
  state: QueryState,
): Promise<Record<string, unknown>[]> {
  let operation = createSelectOperation(table, state)
  let result = await database[executeOperation](operation)

View on GitHub (pinned to 9696913134)

Solutions

  1. Regenerate the query via the normal builder API instead of replaying a stored snapshot
  2. If you persist snapshots, version-stamp them and invalidate after upgrading @remix-run/data-table
  3. If you maintain a fork, add a matching case for your custom mode in executeQuery
Defensive patterns

Strategy: validation

Validate before calling

let supported = new Set(['select', 'insert', 'insertMany', 'update', 'delete', 'upsert'])
if (!supported.has(plan.mode)) throw new Error('Unsupported mode: ' + plan.mode)

Type guard

function isKnownExecutionMode(mode: string): boolean {
  return ['select','insert','insertMany','update','delete','upsert'].includes(mode)
}

Try / catch

try {
  await executeQuery(database, snapshot)
} catch (error) {
  if (error instanceof DataTableQueryError && error.message === 'Unknown query execution mode') {
    // regenerate the query with the current builder and retry once
  } else throw error
}

Prevention

When it happens

Trigger: Passing a hand-constructed or deserialized query/snapshot whose plan.mode is not one of the supported modes; replaying a query snapshot persisted by an older/newer version of @remix-run/data-table with a different mode enum.

Common situations: Caching or storing query plans in a session/cookie/DB and replaying them after upgrading or downgrading the package; forking or monkey-patching the query builder and introducing a new mode without extending executeQuery.

Related errors


AI-assisted analysis of remix-run/remix@9696913134 (2026-08-27). Data as JSON: /api/errors/9eb6461990a9352d. Report an issue: GitHub.