Fix My Tutorial
Report

Transforming data with Node.js transform streams

Open the original tutorial
Fixed Node.js 22 · checked 17 Oct 2026 · model cost $0.102

With the applied fixes, the tutorial now runs successfully in Node.js 22. The original errors were: step s2 failed because the input file myfile.txt was missing (ENOENT), step s6 used the removed crypto.createCipher API, and step s4 timed out because gunzip.js closed stdout prematurely. The repairs create the missing file, replace createCipher with createCipheriv using scryptSync and a random IV, and add {end:false} to the stdout pipe to allow the process to exit.

4 changes to make it work today

Added by Fix My Tutorial

s1_fix1 · shell workaround new step

Create the input file 'myfile.txt' required by gzip.js and later by encrypt.js.

+echo "Hello, world!\nThis is a test file." > myfile.txt

Sources

Write gzip uncompression script

s3 · write_file workaround

Change the pipe to process.stdout to use {end:false} so the gunzip stream ends without attempting to close stdout, preventing the 180s timeout.

@@ -7,3 +7,3 @@
rstream // reads from myfile.txt.gz
.pipe(gunzip) // uncompresses
- .pipe(process.stdout); // writes to stdout
+ .pipe(process.stdout, { end: false }); // writes to stdout without closing it

Write AES encryption script

s5 · write_file migrate

Replace deprecated crypto.createCipher with createCipheriv, add proper key derivation via scryptSync, generate and store a random salt and IV, and use the 'close' event instead of 'finish'.

@@ -3,13 +3,22 @@
// get your password from safe store
-var password = new Buffer('my secret');
-var aes = crypto.createCipher('aes-256-cbc', password);
+var password = Buffer.from('my secret');
+// generate random salt and IV
+var salt = crypto.randomFillSync(Buffer.alloc(16));
+var iv = crypto.randomFillSync(Buffer.alloc(16));
+// derive 32-byte key for aes-256
+var key = crypto.scryptSync(password, salt, 32, { N: 16384, r: 8, p: 1 });
+var aes = crypto.createCipheriv('aes-256-cbc', key, iv);
var rstream = fs.createReadStream('myfile.txt');
var wstream = fs.createWriteStream('myfile.encrypted');
+
+// write salt and iv first (32 bytes total)
+wstream.write(salt);
+wstream.write(iv);
rstream // reads from myfile.txt
.pipe(aes) // encrypts with aes256
.pipe(wstream) // writes to myfile.encrypted
- .on('finish', function () { // finished
+ .on('close', function () { // finished
console.log('done encrypting');
});

Sources

  • Crypto | Node.js v26.7.0 Documentation[`crypto.randomFill(buffer[, offset][, size], callback)`](crypto.html#cryptorandomfillbuffer-offset-size-callback) [`crypto.randomFillSync(buffer[, offset][, size])`](crypto.html#cryptorandomfillsyncbuffer-offset-size) [`crypto.randomInt([min, ]max[, callback])`](crypto.html#cryptorandomintmin-max-callback) [`crypto.randomUUID([options])`](crypto.html#cryptorandomuuidoptions) [`crypto.randomUUIDv7([options])`](crypto.html#cryptorandomuuidv7options) [`crypto.scrypt(password, salt, keylen[, options], callback)`](crypto.html#cryptoscryptpassword-salt-keylen-options-callback) [`crypto.scryptSync(p
  • "TypeError: crypto.createCipher is not a function — migrating to createCipheriv on Node.js 22 Lambda" - DEV CommunityThis is the durable path. The `--openssl-legacy-provider` flag does not restore `createCipher` — it only re-enables the legacy hash provider for build tools; the removed function is gone regardless.

Write AES decryption script

s7 · write_file migrate

Replace deprecated crypto.createDecipher with createDecipheriv, read the stored salt and IV from the encrypted file header, derive the same key with scryptSync, and start the read stream after the 32-byte header.

@@ -3,10 +3,20 @@
// get your password from safe store
-var password = new Buffer('my secret');
-var aes = crypto.createDecipher('aes-256-cbc',
- password);
-var rstream = fs.createReadStream('myfile.encrypted');
+var password = Buffer.from('my secret');
+// read salt and iv from file (first 32 bytes)
+var fd = fs.openSync('myfile.encrypted', 'r');
+var salt = Buffer.alloc(16);
+var iv = Buffer.alloc(16);
+fs.readSync(fd, salt, 0, 16, 0);
+fs.readSync(fd, iv, 0, 16, 16);
+fs.closeSync(fd);
-rstream // reads from myfile.txt
+// derive key using same salt
+var key = crypto.scryptSync(password, salt, 32, { N: 16384, r: 8, p: 1 });
+var aes = crypto.createDecipheriv('aes-256-cbc', key, iv);
+// read from byte 32 onwards
+var rstream = fs.createReadStream('myfile.encrypted', { start: 32 });
+
+rstream // reads from myfile.encrypted
.pipe(aes) // decrypt with aes256
.pipe(process.stdout); // output stdout

Sources

  • Crypto | Node.js v26.7.0 Documentation[`crypto.randomFill(buffer[, offset][, size], callback)`](crypto.html#cryptorandomfillbuffer-offset-size-callback) [`crypto.randomFillSync(buffer[, offset][, size])`](crypto.html#cryptorandomfillsyncbuffer-offset-size) [`crypto.randomInt([min, ]max[, callback])`](crypto.html#cryptorandomintmin-max-callback) [`crypto.randomUUID([options])`](crypto.html#cryptorandomuuidoptions) [`crypto.randomUUIDv7([options])`](crypto.html#cryptorandomuuidv7options) [`crypto.scrypt(password, salt, keylen[, options], callback)`](crypto.html#cryptoscryptpassword-salt-keylen-options-callback) [`crypto.scryptSync(p
  • "TypeError: crypto.createCipher is not a function — migrating to createCipheriv on Node.js 22 Lambda" - DEV CommunityThis is the durable path. The `--openssl-legacy-provider` flag does not restore `createCipher` — it only re-enables the legacy hash provider for build tools; the removed function is gone regardless.

Tell the author

Send them what broke and the fix, so the next reader doesn't hit the same error.

Badge

Add it to the tutorial so readers know when it was last checked.

Fix My Tutorial badge
Markdown
[![Fix My Tutorial](https://fix-my-tutorial.onrender.com/badge/ri-DoVLq51x.svg)](https://fix-my-tutorial.onrender.com/r/ri-DoVLq51x)
HTML
<a href="https://fix-my-tutorial.onrender.com/r/ri-DoVLq51x"><img src="https://fix-my-tutorial.onrender.com/badge/ri-DoVLq51x.svg" alt="Fix My Tutorial"></a>