{"record":{"id":"0d47e5e502114c68","repo":"can1357/oh-my-pi","slug":"sqlite-column-column-only-accepts-json-scalar","errorCode":null,"errorMessage":"SQLite column '${column}' only accepts JSON scalar values or null","messagePattern":"SQLite column '(.+?)' only accepts JSON scalar values or null","errorType":"validation","errorClass":"ToolError","httpStatus":null,"severity":"error","filePath":"packages/coding-agent/src/tools/sqlite-reader.ts","lineNumber":511,"sourceCode":"\tif (!trimmed) return undefined;\n\tconst violation = findWhereClauseViolation(trimmed);\n\tif (violation) {\n\t\tthrow new ToolError(violation);\n\t}\n\treturn trimmed;\n}\n\nfunction normalizeWriteValue(value: unknown, column: string): SqliteBinding {\n\tif (value === null) return null;\n\tif (\n\t\ttypeof value === \"string\" ||\n\t\ttypeof value === \"number\" ||\n\t\ttypeof value === \"boolean\" ||\n\t\ttypeof value === \"bigint\"\n\t) {\n\t\treturn value;\n\t}\n\tthrow new ToolError(`SQLite column '${column}' only accepts JSON scalar values or null`);\n}\n\nfunction validateWriteColumns(\n\tdb: Database,\n\ttable: string,\n\tdata: Record<string, unknown>,\n): Array<[string, SqliteBinding]> {\n\tconst columns = new Set(getTableColumns(db, table));\n\treturn Object.entries(data).map(([column, value]) => {\n\t\tif (!columns.has(column)) {\n\t\t\tthrow new ToolError(`SQLite table '${table}' has no column named '${column}'`);\n\t\t}\n\t\treturn [column, normalizeWriteValue(value, column)];\n\t});\n}\n\nexport function parseSqlitePathCandidates(filePath: string): SqlitePathCandidate[] {\n\tconst normalized = filePath.replace(/\\\\/g, \"/\");","sourceCodeStart":493,"sourceCodeEnd":529,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/packages/coding-agent/src/tools/sqlite-reader.ts#L493-L529","documentation":"Thrown by normalizeWriteValue when a value supplied for a column write is not a JSON scalar (string, number, boolean, bigint) or null. Object/array values cannot be bound as SQLite parameters, so the tool rejects them up front rather than producing an opaque binding error.","triggerScenarios":"Writing data where a field is an object or array, e.g. data={meta:{a:1}} or data={tags:[1,2]}; passing undefined nested values; JSON payloads that keep nested structures instead of flattening or stringifying them.","commonSituations":"Inserting parsed JSON documents directly into a table; forgetting to JSON.stringify nested config blobs; ORM-style code that passes Date objects or arrays.","solutions":["JSON.stringify objects/arrays into strings before writing","Extract scalars from the object and write individual columns","Store arrays/objects as JSON text in a TEXT column","Use null for absent values instead of objects"],"exampleFix":"// before\nwrite('config', { meta: { a: 1 } })\n// after\nwrite('config', { meta: JSON.stringify({ a: 1 }) })","handlingStrategy":"type-guard","validationCode":"function isBindable(v: unknown): boolean {\n  return v === null || ['string','number','boolean','bigint'].includes(typeof v);\n}\nfor (const [k, v] of Object.entries(data)) {\n  if (!isBindable(v)) throw new Error(`column '${k}' needs a scalar or null; stringify objects first`);\n}","typeGuard":"function isSqliteBinding(v: unknown): v is string | number | boolean | bigint | null {\n  return v === null || typeof v === 'string' || typeof v === 'number' || typeof v === 'boolean' || typeof v === 'bigint';\n}","tryCatchPattern":"try {\n  await writer.write('config', data);\n} catch (err) {\n  if (err instanceof ToolError && err.message.includes('only accepts JSON scalar values')) {\n    // stringify nested values and retry once\n  } else throw err;\n}","preventionTips":["Flatten or JSON.stringify nested objects/arrays before writing","Type your write payloads as Record<string, string|number|boolean|null>","Convert Date values to ISO strings before writing"],"tags":["sqlite","validation","data-type","write"],"backgroundTag":"invalid-bind-value-type","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}