{"record":{"id":"7ad49b24d4451964","repo":"FuelLabs/fuels-ts","slug":"invalid-credentials-7ad49b","errorCode":"INVALID_CREDENTIALS","errorMessage":"Invalid credentials.","messagePattern":"Invalid credentials\\.","errorType":"exception","errorClass":"FuelError","httpStatus":null,"severity":"error","filePath":"packages/crypto/src/node/aes-ctr.ts","lineNumber":74,"sourceCode":" */\nexport const decrypt: CryptoApi['decrypt'] = async <T>(\n  password: string,\n  keystore: Keystore\n): Promise<T> => {\n  const iv = bufferFromString(keystore.iv);\n  const salt = bufferFromString(keystore.salt);\n  const secret = keyFromPassword(password, salt);\n  const encryptedText = bufferFromString(keystore.data);\n\n  const decipher = await crypto.createDecipheriv(ALGORITHM, secret, iv);\n  const decrypted = decipher.update(encryptedText);\n  const deBuff = Buffer.concat([decrypted, decipher.final()]);\n  const decryptedData = Buffer.from(deBuff).toString('utf-8');\n\n  try {\n    return JSON.parse(decryptedData);\n  } catch {\n    throw new FuelError(ErrorCode.INVALID_CREDENTIALS, 'Invalid credentials.');\n  }\n};\n","sourceCodeStart":56,"sourceCodeEnd":77,"githubUrl":"https://github.com/FuelLabs/fuels-ts/blob/b3f37c91aca4aa9d5e4c0d3967f66237190826ea/packages/crypto/src/node/aes-ctr.ts#L56-L77","documentation":"Thrown by the Node AES-256-CTR decrypt path when JSON.parse of the decrypted plaintext fails. A failed parse means the ciphertext did not decode to valid JSON, which happens when the derived key is wrong (wrong password) or the keystore blob is not the one originally encrypted. The SDK deliberately collapses both parse failure and authentication failure into a single INVALID_CREDENTIALS error so as not to leak which step failed.","triggerScenarios":"Calling `decrypt(password, keystore)` from @fuel-ts/crypto with a password whose PBKDF2-derived key does not reproduce the original ciphertext, or with a keystore whose `data`, `iv`, or `salt` fields were altered.","commonSituations":"Typo in the wallet password, loading the wrong keystore file, a keystore generated by a different SDK/version or a non-Fuel tool, keystore truncated or corrupted on disk, or copy/paste of keystore fields that dropped characters.","solutions":["Re-enter the password carefully (the failure most often is a wrong password, not corruption).","Confirm the keystore object is the exact one returned by `encrypt()` — match `data`, `iv`, and `salt`.","If migrating from another tool, re-encrypt with `encrypt(password, data)` from this SDK first.","Restore the keystore from a backup if the file was edited or partially overwritten."],"exampleFix":"// before\nconst wallet = await decrypt(typedPassword, keystore);\n// after — verify keystore shape and source first\nif (!keystore.data || !keystore.iv || !keystore.salt) {\n  throw new Error('Keystore is incomplete');\n}\ntry {\n  const wallet = await decrypt(typedPassword, keystore);\n} catch (e) {\n  if (e instanceof FuelError && e.code === FuelError.CODES.INVALID_CREDENTIALS) {\n    // prompt the user to re-enter the password\n  }\n}","handlingStrategy":"try-catch","validationCode":"import { encrypt } from '@fuel-ts/crypto';\n// verify keystore shape and source before decrypt\nfunction isKeystore(o: unknown): o is { data: string; iv: string; salt: string } {\n  return !!o && typeof o === 'object' &&\n    typeof (o as any).data === 'string' &&\n    typeof (o as any).iv === 'string' &&\n    typeof (o as any).salt === 'string';\n}","typeGuard":"import type { Keystore } from '@fuel-ts/crypto';\nconst isKeystore = (o: unknown): o is Keystore =>\n  !!o && typeof o === 'object' &&\n  ['data', 'iv', 'salt'].every((k) => typeof (o as any)[k] === 'string');","tryCatchPattern":"try {\n  const data = await decrypt(password, keystore);\n} catch (e) {\n  if (e instanceof FuelError && e.code === FuelError.CODES.INVALID_CREDENTIALS) {\n    // re-prompt for password; do NOT loop silently\n  }\n  throw e;\n}","preventionTips":["Store the keystore exactly as returned by encrypt(); never edit its fields by hand.","Round-trip test: encrypt then decrypt in the same session to confirm credentials.","Keep backups of keystore + password together; a wrong password is indistinguishable from corruption by design."],"tags":["crypto","credentials","keystore","decryption","authentication"],"backgroundTag":null,"analyzedSha":"b3f37c91aca4aa9d5e4c0d3967f66237190826ea","analyzedAt":"2026-08-12T20:30:56.448Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}