{"record":{"id":"018ca3aba635363b","repo":"clockworklabs/SpacetimeDB","slug":"sql-query-exceeds-maximum-allowed-length-sql","errorCode":null,"errorMessage":"SQL query exceeds maximum allowed length: \\\"{sql:.120}...\\\"","messagePattern":"SQL query exceeds maximum allowed length: \\\\\"(.+?)\\.\\.\\.\\\\\"","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/query/src/lib.rs","lineNumber":32,"sourceCode":"use spacetimedb_physical_plan::{\n    compile::{compile_dml_plan, compile_select, compile_select_list},\n    plan::{ProjectListPlan, ProjectPlan},\n};\nuse spacetimedb_primitives::TableId;\nuse spacetimedb_schema::table_name::TableName;\n\n/// DIRTY HACK ALERT: Maximum allowed length, in UTF-8 bytes, of SQL queries.\n/// Any query longer than this will be rejected.\n/// This prevents a stack overflow when compiling queries with deeply-nested `AND` and `OR` conditions.\nconst MAX_SQL_LENGTH: usize = 50_000;\n\npub fn compile_subscription(\n    sql: &str,\n    tx: &impl SchemaView,\n    auth: &AuthCtx,\n) -> Result<(Vec<ProjectPlan>, TableId, TableName, bool)> {\n    if sql.len() > MAX_SQL_LENGTH {\n        bail!(\"SQL query exceeds maximum allowed length: \\\"{sql:.120}...\\\"\")\n    }\n\n    let (plan, mut has_param) = parse_and_type_sub(sql, tx, auth)?;\n\n    let Some(return_id) = plan.return_table_id() else {\n        bail!(\"Failed to determine TableId for query\")\n    };\n\n    let Some(return_name) = tx.schema_for_table(return_id).map(|schema| schema.table_name.clone()) else {\n        bail!(\"TableId `{return_id}` does not exist\")\n    };\n\n    // Resolve any RLS filters\n    let plan_fragments = resolve_views_for_sub(tx, plan, auth, &mut has_param)?\n        .into_iter()\n        .map(compile_select)\n        .collect::<Vec<_>>();\n","sourceCodeStart":14,"sourceCodeEnd":50,"githubUrl":"https://github.com/clockworklabs/SpacetimeDB/blob/6dee26c6efc2856793e12b148a59742964f5d783/crates/query/src/lib.rs#L14-L50","documentation":"compile_subscription rejects any SQL text longer than 50,000 UTF-8 bytes (MAX_SQL_LENGTH). The cap is a deliberate guard, flagged as a 'DIRTY HACK' in source, against stack overflow when the compiler recurses over queries with deeply nested AND/OR condition trees.","triggerScenarios":"Calling subscribe with a SQL string over 50,000 bytes, typically machine-generated WHERE clauses with hundreds or thousands of OR'd predicates (big IN-list expansions).","commonSituations":"Dynamically building a subscription from a large entity/id list; clients concatenating per-key predicates into one query; generated SQL from ORMs or scripts pasted into clients.","solutions":["Replace long OR/IN chains with a join against a table containing the keys, or filter on a scalar column.","Split the subscription into several smaller subscriptions and merge results client-side.","Persist the filter keys via a reducer into a helper table and subscribe with a join against it."],"exampleFix":"-- before: thousands of OR'd predicates, > 50KB\nSELECT * FROM t WHERE id = 1 OR id = 2 OR id = 3 /* ... */;\n\n-- after: keys live in a table, query stays tiny\nSELECT t.* FROM t JOIN selected_ids s ON t.id = s.id;","handlingStrategy":"validation","validationCode":"// client-side guard before subscribing (limit is 50_000 UTF-8 bytes)\nconst MAX_SQL_LENGTH = 50_000;\nif (new TextEncoder().encode(sql).length > MAX_SQL_LENGTH) {\n  throw new Error(`SQL too large (${sql.length} bytes); split or use a helper-table join`);\n}","typeGuard":null,"tryCatchPattern":"try {\n  await db.subscription.build([sql]).subscribe();\n} catch (e: any) {\n  if (String(e.message).includes(\"exceeds maximum allowed length\")) {\n    // split into multiple smaller subscriptions, or join a keys table\n  }\n}","preventionTips":["Never build subscriptions by string-concatenating per-id predicates; join a keys table instead.","Keep subscription SQL hand-written and short; generate data, not queries.","Add a byte-length assert on SQL strings in test suites that generate queries."],"tags":["sql","subscription","query-limits","input-validation"],"backgroundTag":"query-too-large","analyzedSha":"6dee26c6efc2856793e12b148a59742964f5d783","analyzedAt":"2026-08-20T06:08:37.179Z","contentChangedAt":"2026-08-20T06:08:37.179Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}