{"record":{"id":"ac37757c99a2e751","repo":"usebruno/bruno","slug":"aes256-decryption-failed-fallbackerr-message","errorCode":null,"errorMessage":"AES256 decryption failed: ${fallbackErr.message}","messagePattern":"AES256 decryption failed: (.+?)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/bruno-electron/src/utils/encryption.js","lineNumber":65,"sourceCode":"  const iv = Buffer.alloc(16, 0); // Default IV for new encryption\n  const key = crypto.createHash('sha256').update(rawKey).digest(); // Derive a 32-byte key\n\n  try {\n    const decipher = crypto.createDecipheriv('aes-256-cbc', key, iv);\n    let decrypted = decipher.update(data, 'hex', 'utf8');\n    decrypted += decipher.final('utf8');\n    return decrypted;\n  } catch (err) {\n    // If decryption fails, fall back to old key derivation\n    try {\n      const { key: oldKey, iv: oldIv } = deriveKeyAndIv(rawKey, 32, 16);\n      const decipher = crypto.createDecipheriv('aes-256-cbc', oldKey, oldIv);\n      const decrypted = decipher.update(data, 'hex', 'utf8');\n      decrypted += decipher.final('utf8');\n      return decrypted;\n    } catch (fallbackErr) {\n      console.error('AES256 decryption failed with both methods:', err, fallbackErr);\n      throw new Error('AES256 decryption failed: ' + fallbackErr.message);\n    }\n  }\n}\n\n// electron safe storage encryption and decryption functions\nfunction safeStorageEncrypt(str) {\n  let encryptedStringBuffer = safeStorage.encryptString(str);\n\n  // Convert the encrypted buffer to a hexadecimal string\n  const encryptedString = encryptedStringBuffer.toString('hex');\n\n  return encryptedString;\n}\nfunction safeStorageDecrypt(str) {\n  try {\n    // Convert the hexadecimal string to a buffer\n    const encryptedStringBuffer = Buffer.from(str, 'hex');\n","sourceCodeStart":47,"sourceCodeEnd":83,"githubUrl":"https://github.com/usebruno/bruno/blob/9bdd81c7bdc57006e5f5ebffb79321a8d979f712/packages/bruno-electron/src/utils/encryption.js#L47-L83","documentation":"Thrown by aes256Decrypt when both the new SHA256-key decryption and the legacy MD5-based deriveKeyAndIv decryption fail. The two-step attempt exists to read blobs encrypted before the key-derivation changed. Failure means the data could not be unwrapped with either the current or the legacy scheme using the supplied key.","triggerScenarios":"Passing the wrong passkey (or the wrong machineIdSync-derived key) for an AES256_ALGO ('$01:...') blob; data corrupted/truncated; value migrated across machines whose machine-id differs and no passkey was supplied.","commonSituations":"Copying encrypted secrets between machines without the originating machine-id; passkey mismatch after a credentials reset; partial hex corruption from a bad copy/paste; version downgrade trying to read data encrypted by a newer scheme.","solutions":["Ensure the same passkey used to encrypt is supplied to decrypt (for AES256_ALGO passkey-protected values).","For machine-bound secrets, decrypt on the originating machine or re-encrypt with an explicit passkey before migrating.","If the value is irrecoverable, treat it as lost and re-enter the secret through the UI.","Verify the stored hex is intact (even length, no whitespace)."],"exampleFix":"// before\ntry {\n  // new method\n} catch (err) {\n  try {\n    // legacy method\n  } catch (fallbackErr) {\n    throw new Error('AES256 decryption failed: ' + fallbackErr.message);\n  }\n}\n\n// after: prefer decryptStringSafe at call sites\nconst { success, value, error } = decryptStringSafe(stored);\nif (!success) return { recoverable: false, reason: error };","handlingStrategy":"fallback","validationCode":"const { success, value, error } = decryptStringSafe(stored);\nif (!success) {\n  // wrong passkey or wrong machine; re-prompt the user\n  return await promptUserToReenterSecret();\n}","typeGuard":"function looksLikeAes256Cipher(str) {\n  return typeof str === 'string' && str.startsWith('$01:') && str.length > 4 && str.length % 2 === 0;\n}","tryCatchPattern":"try {\n  return aes256Decrypt(data, passkey);\n} catch (err) {\n  if (err.message.startsWith('AES256 decryption failed')) {\n    // value is irrecoverable on this machine/passkey; re-create the secret\n    return null;\n  }\n  throw err;\n}","preventionTips":["Use a stable explicit passkey rather than machineIdSync for secrets that may migrate.","Re-encrypt secrets on the source machine before moving them.","Prefer decryptStringSafe at call sites to convert failures into recoverable results."],"tags":["encryption","secrets","cross-machine","key-derivation"],"backgroundTag":null,"analyzedSha":"9bdd81c7bdc57006e5f5ebffb79321a8d979f712","analyzedAt":"2026-08-13T04:09:25.751Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}