{"id":"8f6ca339dfa3eb90","repo":"brianc/node-postgres","slug":"callback-is-not-a-function","errorCode":null,"errorMessage":"callback is not a function","messagePattern":"callback is not a function","errorType":"exception","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"packages/pg/lib/client.js","lineNumber":656,"sourceCode":"        if (typeof values === 'function') {\n          query.callback = values\n        } else if (callback) {\n          query.callback = callback\n        }\n      }\n    } else {\n      query = new Query(config, values, callback)\n      if (!query.callback) {\n        result = new this._Promise((resolve, reject) => {\n          query.callback = (err, res) => (err ? reject(err) : resolve(res))\n        }).catch((err) => {\n          // replace the stack trace that leads to `TCP.onStreamRead` with one that leads back to the\n          // application that created the query\n          Error.captureStackTrace(err)\n          throw err\n        })\n      } else if (typeof query.callback !== 'function') {\n        throw new TypeError('callback is not a function')\n      }\n    }\n\n    const readTimeout = config.query_timeout || this.connectionParameters.query_timeout\n    if (readTimeout) {\n      const queryCallback = query.callback || (() => {})\n\n      const readTimeoutTimer = setTimeout(() => {\n        const error = new Error('Query read timeout')\n\n        process.nextTick(() => {\n          query.handleError(error, this.connection)\n        })\n\n        queryCallback(error)\n\n        // we already returned an error,\n        // just do nothing if query completes","sourceCodeStart":638,"sourceCodeEnd":674,"githubUrl":"https://github.com/brianc/node-postgres/blob/c5e8c9a57bff6d9160ec5dbd5c4f4c1e4c460711/packages/pg/lib/client.js#L638-L674","documentation":"Thrown synchronously (as a TypeError) by Client.prototype.query when a Query is constructed with a callback value that is truthy but not a function. In client.js:645-657, after new Query(config, values, callback), if query.callback is truthy but typeof query.callback !== 'function', the library rejects it. This happens when the third positional argument to query(), or config.callback on a config object, is a non-function truthy value (number, string, object). The library refuses to silently accept a broken callback because every code path that uses query.callback calls it.","triggerScenarios":"client.query('SELECT 1', [], 'notafunc'), client.query({ text: 'SELECT 1', callback: 42 }), or passing a value where the third arg is an object instead of a function. normalizeQueryConfig (utils.js:154-155) assigns any truthy callback directly to config.callback without type-checking, so the guard in client.js catches it.","commonSituations":"Passing values array in the wrong position (e.g., client.query(text, callback, values) instead of client.query(text, values, callback)). A config object with a stale callback property left over from refactoring. Misunderstanding the overload signatures of client.query.","solutions":["Ensure the third argument to client.query(text, values, callback) is a function or omitted.","If using a config object, ensure config.callback is a function or remove it to use the returned promise instead.","Switch to async/await with client.query(text, values) and drop the callback argument entirely."],"exampleFix":"// before\nclient.query('SELECT $1', cb, [1]); // wrong argument order\n\n// after\nclient.query('SELECT $1', [1], cb); // (text, values, callback)\n// or\nconst res = await client.query('SELECT $1', [1]);","handlingStrategy":"type-guard","validationCode":"function isFunction(v) {\n  return typeof v === 'function';\n}\n\n// before calling:\nif (callback !== undefined && !isFunction(callback)) {\n  throw new TypeError('callback must be a function');\n}\nclient.query(text, values, callback);","typeGuard":"function isValidCallback(cb) {\n  return cb === undefined || typeof cb === 'function';\n}\n\n// usage:\nif (isValidCallback(cb)) {\n  client.query(text, values, cb);\n}","tryCatchPattern":"try {\n  client.query(text, values, callback);\n} catch (err) {\n  if (err instanceof TypeError && /callback is not a function/i.test(err.message)) {\n    // drop the bad callback and use the promise instead\n    return client.query(text, values);\n  }\n  throw err;\n}","preventionTips":["Use async/await and drop positional callback arguments entirely.","Memorize the overload order: client.query(text, values, callback) — callback is always third.","Never set config.callback to a non-function; if migrating to promises, remove the callback property."],"tags":["query","callback","typeerror","validation"],"analyzedSha":"c5e8c9a57bff6d9160ec5dbd5c4f4c1e4c460711","analyzedAt":"2026-08-03T18:47:28.334Z","schemaVersion":2}