{"record":{"id":"2b8b831dadc3fe1a","repo":"cube-js/cube","slug":"unsupported-parameter-type-for-sql-escaping-typ","errorCode":null,"errorMessage":"Unsupported parameter type for SQL escaping: ${typeof value}","messagePattern":"Unsupported parameter type for SQL escaping: (.+?)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/cubejs-backend-shared/src/sql-escape.ts","lineNumber":131,"sourceCode":"        if (typeof obj.toSqlString === 'function') {\n          return String(obj.toSqlString());\n        }\n\n        if (stringifyObjects) {\n          return this.escapeString(String(value));\n        }\n\n        return Object.keys(value)\n          .filter((key) => typeof (value as Record<string, unknown>)[key] !== 'function')\n          .map((key) => (\n            `${this.escapeIdentifier(key)} = ${\n              this.escapeValueInternal((value as Record<string, unknown>)[key], true)\n            }`\n          ))\n          .join(', ');\n      }\n      default:\n        throw new Error(`Unsupported parameter type for SQL escaping: ${typeof value}`);\n    }\n  }\n\n  /**\n   * Substitutes positional placeholders in `sql` with escaped `values`:\n   *   - `?`  is replaced by an escaped value ({@link escapeValue})\n   *   - `??` is replaced by an escaped identifier ({@link escapeIdentifier})\n   * Longer runs of `?` are left untouched. This mirrors `sqlstring.format`'s\n   * placeholder semantics so it can be a drop-in replacement in drivers.\n   */\n  public format(sql: string, values?: unknown): string {\n    if (values === null || values === undefined) {\n      return sql;\n    }\n\n    const valueList = Array.isArray(values) ? values : [values];\n    if (valueList.length === 0) {\n      return sql;","sourceCodeStart":113,"sourceCodeEnd":149,"githubUrl":"https://github.com/cube-js/cube/blob/7d981676b36392fec34088b9afab6bdcad40207c/packages/cubejs-backend-shared/src/sql-escape.ts#L113-L149","documentation":"escapeValueInternal in packages/cubejs-backend-shared/src/sql-escape.ts throws when asked to SQL-escape a value whose runtime type is not one of the supported kinds (string, number, boolean, arrays, plain objects/records). The switch over `typeof value` reaches its `default` arm, meaning the library cannot safely serialize the value into a SQL literal. This is a fail-fast guard against injecting malformed or unsafe SQL parameters.","triggerScenarios":"Calling escapeValue() (directly or via positional `?` placeholder substitution) with a value of type undefined, function, symbol, bigint, or another exotic type — e.g. escapeValue(undefined) or a params array containing an unset variable or a callback.","commonSituations":"Building query strings dynamically where a variable was never assigned (undefined), passing a Date-like wrapper class instance, passing a function returned from a factory instead of its result, or refactors that change a param type from number to bigint.","solutions":["Log/inspect the offending params array and find the value whose typeof is unsupported (the message names the type).","Coerce undefined/null values explicitly before escaping (e.g. use null and ensure the switch handles it, or stringify the value).","Convert unsupported types to supported primitives: String(v) for symbols, Number(v) for bigint if safe, call the function to get its value.","For structured values, pass a plain object or array so the record-branch of escapeValueInternal escapes it key by key."],"exampleFix":"// before\nconst params = [userId, callbackFn];\nconst sql = substitute(sqlTemplate, params); // throws: Unsupported parameter type... function\n\n// after\nconst params = [userId, callbackFn()]; // pass the value, not the function\nconst sql = substitute(sqlTemplate, params);","handlingStrategy":"type-guard","validationCode":"const SUPPORTED = ['string', 'number', 'boolean', 'object'];\nparams.forEach((v, i) => {\n  if (v == null) throw new Error(`params[${i}] is ${v}; pass an explicit value`);\n  if (!SUPPORTED.includes(typeof v)) throw new Error(`params[${i}] has unsupported type ${typeof v}`);\n});","typeGuard":"function isSqlEscapable(v: unknown): v is string | number | boolean | Record<string, unknown> | unknown[] {\n  return v != null && ['string', 'number', 'boolean', 'object'].includes(typeof v);\n}","tryCatchPattern":"try {\n  const sql = substitute(template, params);\n} catch (e) {\n  if (/Unsupported parameter type for SQL escaping/.test(String(e))) {\n    throw new Error(`Bad SQL params at indexes: ${params.map((p,i)=>[p,i]).filter(([p])=>!isSqlEscapable(p)).map(([,i])=>i)}`);\n  }\n  throw e;\n}","preventionTips":["Never build params from possibly-unset variables without defaults (value ?? fallback)","Call functions before placing their results in params arrays","Convert exotic types (bigint, symbol, Date wrappers) to string/number explicitly","Keep param construction close to the query so types are visible in review"],"tags":["sql","escaping","parameter-validation","runtime"],"backgroundTag":"unsupported-sql-param-type","analyzedSha":"7d981676b36392fec34088b9afab6bdcad40207c","analyzedAt":"2026-09-02T03:45:10.400Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T15:18:49.778Z"}