Skip to content

options.defaultEncoding not validated in stream.Writable constructor #46301

Closed
@Alexthemediocre

Description

@Alexthemediocre

Version

v19.4.0

Platform

Microsoft Windows NT 10.0.22000.0 x64

Subsystem

node:stream

What steps will reproduce the bug?

Create a new stream.Writeable and supply an invalid encoding for defaultEncoding. It will accept the encoding just fine, which can lead to some strange side effects.

For a very quick test, just to show that it does not validate it:

new (require('node:stream').Writable)({defaultEncoding: 'some invalid encoding'});

For a more complete test that shows more of its effects:

const stream = require('node:stream');

console.log('stream 1');
const s1 = new stream.Writable({
   defaultEncoding: 'my invalid encoding',
   write(chunk, enc, cb) {
      console.log('dat', chunk);
      console.log('enc', enc);
      cb();
   }
});
// output:
//TypeError: Unknown encoding: my invalid encoding
//...
try {
   s1.write('test data');
} catch (err) {
   console.error(err);
}

/* ============================== */

console.log('\nstream 2');
const s2 = new stream.Writable({
   defaultEncoding: 'my invalid encoding',
   decodeStrings: false,
   write(chunk, enc, cb) {
      console.log('dat', chunk);
      console.log('enc', enc);
      cb();
   }
});
// output:
//dat test data
//enc my invalid encoding
s2.write('test data');

/* ============================== */

console.log('\nstream 3');
const s3 = new stream.Writable({
   defaultEncoding: {an: 'object'},
   write(chunk, enc, cb) {
      console.log('dat', chunk);
      console.log('enc', enc);
      cb();
   }
});
// output:
//dat <Buffer 74 65 73 74 20 64 61 74 61>
//enc buffer
s3.write('test data');

/* ============================== */

console.log('\nstream 4');
const s4 = new stream.Transform({
   defaultEncoding: 'my invalid encoding',
   transform(chunk, enc, cb) {
      console.log('dat', chunk);
      console.log('enc', enc);
      cb(chunk);
   }
});
// output:
//TypeError: Unknown encoding: my invalid encoding
//...
try {
   s4.write('test data');
} catch (err) {
   console.error(err);
}

/* ============================== */

console.log('\nnode:crypto test');
console.log('crypto.createCipheriv');

const crypto = require('node:crypto');
const encrypt = crypto.createCipheriv('aes-128-gcm', crypto.randomBytes(16), crypto.randomBytes(16), {defaultEncoding: 'an invalid encoding'});

encrypt.on('data', (chunk) => {
   console.log('data received', chunk);
});
encrypt.write('some more data');
encrypt.end();

How often does it reproduce? Is there a required condition?

As far as I can tell, it always reproduces.

What is the expected behavior?

I would expect the stream.Writeable constructor to validate the defaultEncoding option and throw an error if it is invalid.

It still can throw an error with a call to writeable.write if objectMode is false, decodeStrings is true, the chunk is a string, and no encoding is specified in the write call. Weirdly enough, it doesn't throw an error if the defaultEncoding is something other than a string, like a number or object, and converts the string provided in the write call to a buffer anyway.

const stream = require('node:stream');
// would expect an error
new stream.Writable({defaultEncoding: 'some invalid encoding'});

// would very much expect an error
new stream.Writable({defaultEncoding: 42}).write('a string');

const s = new stream.Writeable();
// throws an error, which is exactly what I would expect
s.setDefaultEncoding('some invalid encoding');

// also throws an error (expected)
s.write('a string', 42);

What do you see instead?

It does not validate invalid default encodings in the constructor, and only throws an error if the invalid default encoding is used (such as if a string is provided in a write call with no other encoding specified).

Additional information

Trying a similar thing with stream.Readable throws an error instead.

// throws an error (which is expected)
new (require('node:stream').Readable)({encoding: 'some invalid encoding'});

Metadata

Metadata

Assignees

No one assigned

    Labels

    streamIssues and PRs related to the stream subsystem.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions