{"record":{"id":"29b63d4654063c0a","repo":"TencentCloud/TencentDB-Agent-Memory","slug":"invalid-scrypt-parameter-raw","errorCode":null,"errorMessage":"Invalid scrypt parameter: ${raw}","messagePattern":"Invalid scrypt parameter: (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"MemoryCore/src/metadata/utils/crypto.ts","lineNumber":87,"sourceCode":"  if (pepper.length !== PEPPER_LEN) {\n    throw new Error(\n      `TDAI_PASSWORD_PEPPER must decode to ${PEPPER_LEN} bytes, got ${pepper.length}`,\n    );\n  }\n\n  const scryptN = parsePositiveInt(env.TDAI_PASSWORD_SCRYPT_N, DEFAULT_SCRYPT_N);\n  const scryptR = parsePositiveInt(env.TDAI_PASSWORD_SCRYPT_R, DEFAULT_SCRYPT_R);\n  const scryptP = parsePositiveInt(env.TDAI_PASSWORD_SCRYPT_P, DEFAULT_SCRYPT_P);\n  const keylen = parsePositiveInt(env.TDAI_PASSWORD_SCRYPT_KEYLEN, DEFAULT_SCRYPT_KEYLEN);\n\n  return { pepper, scryptN, scryptR, scryptP, keylen };\n}\n\nfunction parsePositiveInt(raw: string | undefined, fallback: number): number {\n  if (!raw?.trim()) return fallback;\n  const n = Number(raw);\n  if (!Number.isFinite(n) || n <= 0 || !Number.isInteger(n)) {\n    throw new Error(`Invalid scrypt parameter: ${raw}`);\n  }\n  return n;\n}\n\nfunction scryptHash(plain: string, salt: Buffer, config: PasswordHashConfig): Buffer {\n  const input = Buffer.concat([config.pepper, Buffer.from(plain, \"utf8\")]);\n  return scryptSync(input, salt, config.keylen, {\n    N: config.scryptN,\n    r: config.scryptR,\n    p: config.scryptP,\n  });\n}\n\n/**\n * 对明文密码做 scrypt+pepper 哈希，返回自描述存库串。\n *\n * 格式：`$scrypt$N,r,p$<salt_b64>$<hash_b64>`\n */","sourceCodeStart":69,"sourceCodeEnd":105,"githubUrl":"https://github.com/TencentCloud/TencentDB-Agent-Memory/blob/3efcd317b84146d6a08518ac0f7ee7c8a8d200ec/MemoryCore/src/metadata/utils/crypto.ts#L69-L105","documentation":"parsePositiveInt validates SCRYPT_N/R/P env values and the derived keylen before they reach the scrypt KDF. It throws when a raw env string is non-empty but is not a finite positive integer (e.g. 'abc', '0', '2.5', '-1'), because invalid scrypt cost parameters would either crash the KDF or weaken hashing. The fallback is only used when the variable is unset/blank.","triggerScenarios":"Calling scryptN, scryptR, scryptP or keylen with an env var like SCRYPT_N set to a non-integer or non-positive string; e.g. SCRYPT_R='0.5' or SCRYPT_P='abc'.","commonSituations":"Typo in env config ('SCRYPT_N=16_000' — underscores not parsed), quoting errors leaving stray characters, YAML/JSON values pasted into .env, or someone setting 0 or a negative value to 'disable' the parameter.","solutions":["Fix the env variable to a positive integer string, e.g. SCRYPT_N=16384, SCRYPT_R=8, SCRYPT_P=1","Remove the variable entirely to use the built-in fallback value","Trim whitespace/quotes from the .env entry (Number() rejects stray quotes and units like '16k')","Add startup validation that logs parsed scrypt params before hashing begins"],"exampleFix":"// before (.env)\nSCRYPT_N=16,384\n// after (.env)\nSCRYPT_N=16384","handlingStrategy":"validation","validationCode":"function validScryptEnv(v?: string) { if (!v?.trim()) return true; const n = Number(v); return Number.isFinite(n) && n > 0 && Number.isInteger(n); }\nif (!validScryptEnv(process.env.SCRYPT_N) || !validScryptEnv(process.env.SCRYPT_R) || !validScryptEnv(process.env.SCRYPT_P)) throw new Error('SCRYPT_N/R/P must be positive integers');","typeGuard":"const isPositiveIntString = (v: string | undefined): v is string => !!v?.trim() && Number.isInteger(Number(v)) && Number(v) > 0;","tryCatchPattern":"try { cfg = { n: scryptN(), r: scryptR(), p: scryptP() }; } catch (e) { logger.warn(`bad scrypt env: ${e.message}; using fallbacks`); cfg = defaultScryptConfig; }","preventionTips":["Keep SCRYPT_* values as plain integer strings in .env (no commas, units, or underscores)","Validate all scrypt env vars at startup before first hash","Document fallback values so unset vars are the normal path"],"tags":["config","crypto","env-validation"],"backgroundTag":"invalid-env-parameter","analyzedSha":"3efcd317b84146d6a08518ac0f7ee7c8a8d200ec","analyzedAt":"2026-09-01T05:44:22.276Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T15:18:49.778Z"}