# Streaming API Troubleshooting Guide
This guide helps you diagnose and resolve common issues when using the MD5 streaming API.
## Common Issues
### 1. Stream not emitting 'md5' event
**Symptom:**
```typescript
const stream = new MD5Stream();
stream.on('md5', (result) => {
console.log(result.digest); // Never called
});
stream.write('data');
// No 'md5' event emitted
```
**Causes and Solutions:**
**Cause 1:** Stream not ended
```typescript
// Wrong
const stream = new MD5Stream();
stream.on('md5', (result) => console.log(result.digest));
stream.write('data');
// Missing stream.end()
// Correct
stream.end('data');
```
**Cause 2:** Listening to 'md5' after writing
```typescript
// Wrong
const stream = new MD5Stream();
stream.write('data'); // Data processed immediately
stream.on('md5', (result) => console.log(result.digest)); // Too late!
// Correct
const stream = new MD5Stream();
stream.on('md5', (result) => console.log(result.digest));
stream.end('data');
```
**Cause 3:** Empty data without end
```typescript
// Wrong
const stream = new MD5Stream();
stream.write('');
stream.on('md5', (result) => console.log(result.digest));
// 'md5' only emitted after end()
// Correct
stream.end('');
```
---
### 2. Different hash values between implementations
**Symptom:**
```
Expected: 5d41402abc4b2a76b9719d911017c592 (MD5 of "hello")
Got: 8b1a9953c4611296a827abf8c47804d7
```
**Causes and Solutions:**
**Cause 1:** Different data encoding
```typescript
// Wrong - string vs buffer
stream.end('hello'); // String
// vs
stream.end(Buffer.from([104, 101, 108, 108, 111])); // Same data
// Both should work if data is equivalent
```
**Cause 2:** Extra whitespace or characters
```typescript
// Wrong
const data1 = 'hello'; // 5 bytes
const data2 = 'hello\n'; // 6 bytes (includes newline)
// Check exact bytes
console.log(Buffer.byteLength('hello')); // 5
console.log(Buffer.byteLength('hello\n')); // 6
```
**Cause 3:** Different add32 function in testing
```typescript
// If using custom add32, results may differ
const customAdd32 = (x, y) => (x + y) & 0xffffffff;
const stream = new MD5Stream({ add32: customAdd32 });
// Results may not match standard MD5
// For standard MD5, omit add32 option
const stream = new MD5Stream();
```
---
### 3. Memory issues with large files
**Symptom:**
```
FATAL ERROR: Ineffective mark-compact near heap limit
```
**Causes and Solutions:**
**Cause 1:** Loading entire file into memory
```typescript
// Wrong
const data = fs.readFileSync('large-file.bin'); // Loads entire file!
const stream = new MD5Stream();
stream.end(data);
// Correct - streaming
const stream = new MD5Stream();
fs.createReadStream('large-file.bin').pipe(stream);
```
**Cause 2:** Large chunk sizes
```typescript
// Wrong - too much data in memory at once
const largeData = 'a'.repeat(100 * 1024 * 1024); // 100MB
stream.end(largeData);
// Correct - chunked writing
const chunkSize = 64 * 1024; // 64KB chunks
for (let i = 0; i < data.length; i += chunkSize) {
const chunk = data.substring(i, i + chunkSize);
stream.write(chunk);
}
stream.end();
```
**Cause 3:** Not reusing stream instances
```typescript
// Wrong - creates many stream instances
files.forEach(file => {
const stream = new MD5Stream();
// ... hash file
});
// Correct - reuse or single use
const stream = new MD5Stream();
files.forEach(file => {
// ... hash file
stream.reset();
});
```
---
### 4. Stream errors not being handled
**Symptom:**
```
Uncaught Error: ENOENT: no such file or directory
```
**Solution:**
```typescript
const stream = new MD5Stream();
stream.on('error', (error) => {
console.error('Stream error:', error.message);
});
stream.on('md5', (result) => {
console.log('MD5:', result.digest);
});
fs.createReadStream('nonexistent.txt').pipe(stream);
```
**Also:**
```typescript
const { stream, result } = fromStream(fs.createReadStream('file.txt'));
result.catch((error) => {
console.error('Hashing error:', error.message);
});
```
---
### 5. Browser: FileReader not working
**Symptom:**
```
ReferenceError: FileReader is not defined
```
**Cause:**
FileReader is not available in all Node.js environments.
**Solutions:**
**Solution 1:** Check availability
```typescript
if (typeof FileReader !== 'undefined') {
// Use FileReader
} else {
// Fallback for Node.js
}
```
**Solution 2:** Use direct hashBlob
```typescript
import { hashBlob } from 'pure-md5';
const blob = new Blob([data]);
const result = await hashBlob(blob);
```
**Solution 3:** Polyfill WHATWG Streams
```html
```
---
### 6. Unicode character encoding issues
**Symptom:**
```
MD5 of "café" differs between implementations
```
**Cause:**
Different character encoding (UTF-8 vs UTF-16).
**Solution:**
```typescript
import { MD5Stream } from 'pure-md5';
const text = 'café';
// Node.js Buffer uses UTF-8 by default
const stream = new MD5Stream();
let result = '';
stream.on('md5', (r) => result = r.digest);
stream.end(text); // UTF-8 encoding
// To verify encoding
console.log(Buffer.byteLength(text, 'utf8')); // 5 bytes for "café"
```
---
### 7. reset() not working as expected
**Symptom:**
```typescript
const stream = new MD5Stream();
stream.write('first');
stream.reset();
stream.write('second');
// Still getting hash of 'first'
```
**Cause:**
Stream already ended, then reset.
**Solution:**
```typescript
const stream = new MD5Stream();
// First computation
stream.on('md5', (result) => {
console.log('First:', result.digest);
// Reset ONLY after first computation completes
stream.reset();
// Start new computation
stream.write('second');
stream.end();
});
stream.on('md5', (result) => {
console.log('Second:', result.digest);
});
stream.write('first');
stream.end();
```
**Better approach:**
```typescript
// Use separate instances
const stream1 = new MD5Stream();
stream1.on('md5', (result) => console.log('First:', result.digest));
stream1.write('first');
stream1.end();
const stream2 = new MD5Stream();
stream2.on('md5', (result) => console.log('Second:', result.digest));
stream2.write('second');
stream2.end();
```
---
### 8. Async/await with MD5Stream
**Symptom:**
```
SyntaxError: await is only valid in async function
```
**Solution:**
```typescript
// Wrong - await not in async function
const stream = new MD5Stream();
let result;
stream.on('md5', (r) => result = r);
stream.end('data');
await new Promise(resolve => stream.on('finish', resolve)); // Error!
// Correct - wrap in async function
async function hashString(data) {
return new Promise((resolve, reject) => {
const stream = new MD5Stream();
stream.on('md5', (result) => resolve(result));
stream.on('error', reject);
stream.end(data);
});
}
// Usage
const result = await hashString('data');
console.log(result.digest);
```
**Alternative with fromStream:**
```typescript
import { fromStream } from 'pure-md5';
import { Readable } from 'stream';
const { result } = fromStream(Readable.from(['data']));
const resultData = await result;
console.log(resultData.digest);
```
---
### 9. Chunked data not processed correctly
**Symptom:**
```typescript
const stream = new MD5Stream();
stream.on('md5', (result) => {
console.log(result.digest);
});
stream.write('he');
stream.write('llo');
// Only "he" is being hashed
```
**Cause:**
Not ending the stream after all chunks.
**Solution:**
```typescript
const stream = new MD5Stream();
stream.on('md5', (result) => {
console.log(result.digest); // Now shows hash of "hello"
});
stream.write('he');
stream.write('llo');
stream.end(); // Must end stream
```
---
### 10. Type errors in TypeScript
**Symptom:**
```
TS2304: Cannot find name 'Readable'
```
**Solution:**
```typescript
import { MD5Stream, fromStream } from 'pure-md5';
import { Readable } from 'stream'; // Import Readable
const source = Readable.from(['data']);
const { result } = fromStream(source);
```
---
## Testing and Debugging
### Debugging State
```typescript
const stream = new MD5Stream();
console.log('Initial:', stream.getCurrentState());
stream.write('test');
console.log('After write:', stream.getCurrentState());
console.log('Bytes processed:', stream.getBytesProcessed());
stream.on('md5', (result) => {
console.log('Final digest:', result.digest);
});
```
### Verifying Hash Correctness
```typescript
import { md5Core } from 'pure-md5';
import { MD5Stream } from 'pure-md5';
const testString = 'The quick brown fox jumps over the lazy dog';
const expectedHash = md5Core(testString); // Known correct MD5
const stream = new MD5Stream();
stream.on('md5', (result) => {
console.log('Expected:', expectedHash);
console.log('Got: ', result.digest);
console.log('Match: ', result.digest === expectedHash);
});
stream.end(testString);
```
### Testing with Known Values
```
MD5("") = d41d8cd98f00b204e9800998ecf8427e
MD5("a") = 0cc175b9c0f1b6a831c399e269772661
MD5("abc") = 900150983cd24fb0d6963f7d28e17f72
MD5("message digest") = f96b697d7cb7938d525a2f31aaf161d0
MD5("abcdefghijklmnopqrstuvwxyz") = c3fcd3d76192e4007dfb496cca67e13b
```
Use these to verify your implementation:
```typescript
const testCases = [
{ input: '', expected: 'd41d8cd98f00b204e9800998ecf8427e' },
{ input: 'a', expected: '0cc175b9c0f1b6a831c399e269772661' },
{ input: 'abc', expected: '900150983cd24fb0d6963f7d28e17f72' },
];
for (const test of testCases) {
const stream = new MD5Stream();
stream.on('md5', (result) => {
const pass = result.digest === test.expected;
console.log(`Test "${test.input}": ${pass ? 'PASS' : 'FAIL'}`);
});
stream.end(test.input);
}
```
---
## Best Practices
1. **Always handle errors:**
```typescript
stream.on('error', (error) => console.error(error));
```
2. **End streams properly:**
```typescript
stream.end(); // Always call end()
```
3. **Check data consistency:**
```typescript
console.log('Expected:', expected);
console.log('Got: ', result.digest);
```
4. **Use appropriate chunk sizes:**
```typescript
// 64KB is optimal for most cases
const chunkSize = 64 * 1024;
```
5. **Reuse streams when appropriate:**
```typescript
const stream = new MD5Stream();
// ... use stream
stream.reset();
// ... use again
```
---
## Getting Help
If you're still having issues:
1. Check this troubleshooting guide
2. Review the [API documentation](STREAM_API.md)
3. Check existing tests in `__tests__/stream/`
4. Open an issue with:
- Your code example
- Expected vs actual behavior
- Environment details (Node.js version, browser, OS)