{"record":{"id":"78ce6505edf9fd53","repo":"brianc/node-postgres","slug":"sasl-invalid-attribute-pair-entry","errorCode":null,"errorMessage":"SASL: Invalid attribute pair entry","messagePattern":"SASL: Invalid attribute pair entry","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/pg/lib/crypto/sasl.js","lineNumber":183,"sourceCode":" * base64-3        = 3base64-char \"=\"\n *\n * base64-2        = 2base64-char \"==\"\n *\n * base64          = *base64-4 [base64-3 / base64-2]\n */\nfunction isBase64(text) {\n  return /^(?:[a-zA-Z0-9+/]{4})*(?:[a-zA-Z0-9+/]{2}==|[a-zA-Z0-9+/]{3}=)?$/.test(text)\n}\n\nfunction parseAttributePairs(text) {\n  if (typeof text !== 'string') {\n    throw new TypeError('SASL: attribute pairs text must be a string')\n  }\n\n  return new Map(\n    text.split(',').map((attrValue) => {\n      if (!/^.=/.test(attrValue)) {\n        throw new Error('SASL: Invalid attribute pair entry')\n      }\n      const name = attrValue[0]\n      const value = attrValue.substring(2)\n      return [name, value]\n    })\n  )\n}\n\nfunction parseServerFirstMessage(data) {\n  const attrPairs = parseAttributePairs(data)\n\n  const nonce = attrPairs.get('r')\n  if (!nonce) {\n    throw new Error('SASL: SCRAM-SERVER-FIRST-MESSAGE: nonce missing')\n  } else if (!isPrintableChars(nonce)) {\n    throw new Error('SASL: SCRAM-SERVER-FIRST-MESSAGE: nonce must only contain printable characters')\n  }\n  const salt = attrPairs.get('s')","sourceCodeStart":165,"sourceCodeEnd":201,"githubUrl":"https://github.com/brianc/node-postgres/blob/ff9d775abd12f29dd6df03945253b54eabbb29f2/packages/pg/lib/crypto/sasl.js#L165-L201","documentation":"Thrown inside parseAttributePairs() when a comma-separated segment of a SASL message does not match the pattern ^.= (a single character followed by an equals sign). Every SASL attribute pair must follow the form <type-char>=<value>. A segment failing this check means the server sent a structurally malformed SASL message.","triggerScenarios":"text.split(',').map() iterates over each comma-delimited segment. If any segment does not match /^.=/ — for example an empty string (from leading comma, trailing comma, or double comma), a segment missing the equals sign, or a multi-character attribute name — the error fires at sasl.js:182-183.","commonSituations":"Connecting to a non-PostgreSQL server that responds with a non-conformant SASL message; a proxy or connection pooler corrupting the authentication stream by inserting or dropping bytes; network-level data corruption; an intentionally malicious server sending crafted malformed messages.","solutions":["Confirm you are connecting to a real PostgreSQL server (not a mock or incompatible proxy that speaks a different protocol).","Remove any intermediary proxies, load balancers, or SSL terminators between the client and PostgreSQL that might corrupt the auth stream.","Use psql or another client to verify the same connection string authenticates successfully.","Update node-postgres to the latest version for any protocol-handling fixes."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"// Verify you're talking to a real PostgreSQL server:\nconst net = require('net')\nconst sock = net.connect(port, host)\nsock.on('connect', () => { sock.end(); console.log('Port reachable') })\nsock.on('error', (e) => console.error('Cannot reach server:', e.message))","typeGuard":null,"tryCatchPattern":"try {\n  await client.connect()\n} catch (err) {\n  if (err.message.includes('Invalid attribute pair entry')) {\n    throw new Error('Malformed SASL message from server — verify target is PostgreSQL and no proxy is corrupting traffic')\n  }\n  throw err\n}","preventionTips":["Confirm the server is a real PostgreSQL instance, not a protocol-incompatible proxy or mock.","Remove intermediaries (load balancers, custom proxies) that may corrupt the SASL message format.","Enable SSL/TLS to protect authentication data integrity.","Test the connection with psql to establish a baseline."],"tags":["authentication","sasl","scram","protocol-error","connection"],"backgroundTag":null,"analyzedSha":"ff9d775abd12f29dd6df03945253b54eabbb29f2","analyzedAt":"2026-08-11T15:33:59.644Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}