discordjs/discord.js · warning · Error
Failed to parse packet
Error message
Failed to parse packet
What it means
After decrypting an RTP packet, parsePacket checks the decryption result; if decrypt returns a falsy value (empty/failed decrypt) it throws this generic Error. A null/empty payload means decryption produced nothing usable — usually a wrong nonce construction, wrong secret key, or a corrupted/short packet — so the packet cannot be yielded as an Opus frame.
Source
Thrown at packages/voice/src/receive/VoiceReceiver.ts:166
secretKey: Uint8Array,
userId: string,
ssrc: number,
): AudioPacket | null {
// Parse key RTP Header fields
const first = rtp.readUint8();
const hasHeaderExtension = Boolean((first >> 4) & 0x01); // X field
const cc = first & 0x0f; // CSRC Count field
const sequence = rtp.readUInt16BE(2);
const timestamp = rtp.readUInt32BE(4);
// Compute unencrypted header size: fixed header + CSRC Identifiers + extension header if present
let headerSize = 12 + 4 * cc;
const extensionHeaderOffset = headerSize; // where the extension header starts, if present
if (hasHeaderExtension) headerSize += 4; // extension header (profile ID + length)
// Decrypt the RTP Payload
let payload: Buffer = this.decrypt(rtp, mode, nonce, secretKey, headerSize);
if (!payload) throw new Error('Failed to parse packet');
// Strip padding (RFC3550 5.1)
const hasPadding = rtp[0] && Boolean(rtp[0] & 0b100000);
if (hasPadding) {
const paddingAmount = payload[payload.length - 1]!;
if (paddingAmount < payload.length) {
payload = payload.subarray(0, payload.length - paddingAmount);
}
}
// Skip the decrypted RTP Header Extension data if present
if (hasHeaderExtension) {
// Extension Header Length field
const headerExtensionLength = rtp.readUInt16BE(extensionHeaderOffset + 2);
payload = payload.subarray(4 * headerExtensionLength);
}
// Decrypt payload if in a DAVE session.View on GitHub (pinned to a81ed8a306)
Solutions
- Wrap parsePacket/subscribe handlers so corrupt packets are skipped — individual packet loss is expected in RTP and safe to ignore.
- Rejoin the voice channel / recreate the receiver after a reconnect so a fresh secretKey is used.
- Update @discordjs/voice to the latest version to get nonce-handling fixes for your negotiated mode.
- Check network stability (packet loss, VPN/firewall interference) if a large fraction of packets fail.
Example fix
// before
receiver.subscribe(userId); // throws on corrupt packet, killing the pipeline
// after
const sub = receiver.subscribe(userId);
sub.on('error', (e) => {
if (e.message === 'Failed to parse packet') return; // skip corrupt packet
throw e;
}); Defensive patterns
Strategy: try-catch
Validate before calling
// Sanity-check the RTP datagram before parsing:
function isPlausibleRtp(buf: Buffer): boolean {
return buf.length >= 12 && (buf[0]! >> 6) === 2; // version 2, min header length
} Type guard
function isRtpPacket(buf: Buffer): boolean {
return Buffer.isBuffer(buf) && buf.length >= 12 && (buf[0]! & 0xc0) === 0x80;
} Try / catch
try {
const opus = receiver.parsePacket(rtp, mode, nonce, secretKey);
} catch (e) {
if (e.message === 'Failed to parse packet') return; // drop corrupt RTP packet, continue stream
throw e;
} Prevention
- Treat individual packet failures as normal RTP loss — never crash the pipeline for one packet.
- Refresh secretKey/mode on every voice reconnect to avoid decrypting with stale keys.
- Keep @discordjs/voice current for nonce-handling fixes.
- Improve network reliability (wired connection, no UDP-intercepting proxies) to reduce corrupt packets.
When it happens
Trigger: Receiving an RTP packet that fails to decrypt to a non-empty buffer: packets arriving with a mismatched nonce padding for the negotiated mode, key/mode mismatch between the connection and receiver, or malformed/truncated datagrams (e.g. headerSize >= datagram length).
Common situations: Flaky networks dropping/corrupting UDP packets; receiving packets from a different voice session after reconnect (stale secret key); older Discord server behavior with nonce suffix modes; non-audio datagrams hitting the socket.
Understand the failure class
- Parsing and encoding errors: unexpected token, malformed input — why parsers reject input and how to find the real culprit.
Related errors
AI-assisted analysis of discordjs/discord.js@a81ed8a306 (2026-08-30).
Data as JSON: /api/errors/e54fa44235619e97.
Report an issue: GitHub.