{"id":"75e3296f6188bdbe","repo":"brianc/node-postgres","slug":"sslnegotiation-direct-requires-ssl-to-be-enabled","errorCode":null,"errorMessage":"sslnegotiation=direct requires SSL to be enabled","messagePattern":"sslnegotiation=direct requires SSL to be enabled","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/pg/lib/connection-parameters.js","lineNumber":111,"sourceCode":"    if (this.ssl === 'no-verify') {\n      this.ssl = { rejectUnauthorized: false }\n    }\n    if (this.ssl && this.ssl.key) {\n      Object.defineProperty(this.ssl, 'key', {\n        enumerable: false,\n      })\n    }\n\n    // How to negotiate SSL: 'postgres' (default, the traditional SSLRequest\n    // handshake) or 'direct' (start the TLS handshake immediately on connect).\n    this.sslnegotiation = val('sslnegotiation', config, 'PGSSLNEGOTIATION')\n    if (this.sslnegotiation !== undefined && this.sslnegotiation !== 'postgres' && this.sslnegotiation !== 'direct') {\n      throw new Error(\n        `Invalid sslnegotiation value: \"${this.sslnegotiation}\". Valid values are \"postgres\" and \"direct\".`\n      )\n    }\n    if (this.sslnegotiation === 'direct' && !this.ssl) {\n      throw new Error('sslnegotiation=direct requires SSL to be enabled')\n    }\n\n    this.client_encoding = val('client_encoding', config)\n    this.replication = val('replication', config)\n    // a domain socket begins with '/'\n    this.isDomainSocket = !(this.host || '').indexOf('/')\n\n    this.application_name = val('application_name', config, 'PGAPPNAME')\n    this.fallback_application_name = val('fallback_application_name', config, false)\n    this.statement_timeout = val('statement_timeout', config, false)\n    this.lock_timeout = val('lock_timeout', config, false)\n    this.idle_in_transaction_session_timeout = val('idle_in_transaction_session_timeout', config, false)\n    this.query_timeout = val('query_timeout', config, false)\n\n    if (config.connectionTimeoutMillis === undefined) {\n      this.connect_timeout = process.env.PGCONNECT_TIMEOUT || 0\n    } else {\n      this.connect_timeout = Math.floor(config.connectionTimeoutMillis / 1000)","sourceCodeStart":93,"sourceCodeEnd":129,"githubUrl":"https://github.com/brianc/node-postgres/blob/c5e8c9a57bff6d9160ec5dbd5c4f4c1e4c460711/packages/pg/lib/connection-parameters.js#L93-L129","documentation":"Thrown by the ConnectionParameters constructor (connection-parameters.js:110-112) when sslnegotiation is set to 'direct' but SSL is not enabled. Direct SSL negotiation means the client begins the TLS handshake immediately upon TCP connect — there is no plaintext fallback — so it is meaningless without SSL. The guard prevents a configuration that would send a TLS ClientHello to a server expecting a PostgreSQL StartupMessage (or vice versa), which would hang or produce a confusing protocol error.","triggerScenarios":"Passing { sslnegotiation: 'direct' } without an ssl option, or with ssl: false. Also via connection string '?sslnegotiation=direct' without an ssl-related parameter when PGSSLMODE is unset/disable. The check at line 110 tests this.sslnegotiation === 'direct' && !this.ssl.","commonSituations":"Setting sslnegotiation=direct for performance (avoids an extra round-trip) but forgetting to also enable ssl. A deployment where PGSSLMODE was previously set but is now disabled, while PGSSLNEGOTIATION=direct remains.","solutions":["Enable SSL alongside direct negotiation: { ssl: true, sslnegotiation: 'direct' } or add sslmode=require (or higher) to the connection string.","If you do not want SSL, remove sslnegotiation='direct' and use the default 'postgres' mode (which still supports optional SSL via sslmode).","Verify that your PostgreSQL server is configured to accept direct TLS connections (ssl=on in postgresql.conf)."],"exampleFix":"// before\nconst client = new Client({ sslnegotiation: 'direct' }); // ssl not set\n\n// after\nconst client = new Client({ ssl: true, sslnegotiation: 'direct' });\n// or connection string: postgres://host/db?sslmode=require&sslnegotiation=direct","handlingStrategy":"validation","validationCode":"function validateDirectSsl(config) {\n  const neg = config.sslnegotiation ?? process.env.PGSSLNEGOTIATION;\n  if (neg === 'direct' && !config.ssl) {\n    throw new Error('sslnegotiation=direct requires SSL to be enabled (set ssl: true or sslmode=require+).');\n  }\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Always pair sslnegotiation='direct' with an enabled ssl option.","When deploying, set PGSSLMODE=require (or higher) alongside PGSSLNEGOTIATION=direct.","Add a config validator that checks SSL/negotiation consistency before constructing the Client."],"tags":["ssl","config","validation"],"analyzedSha":"c5e8c9a57bff6d9160ec5dbd5c4f4c1e4c460711","analyzedAt":"2026-08-03T18:47:28.334Z","schemaVersion":2}