{"record":{"id":"50b28dc3042d8d27","repo":"discordjs/discord.js","slug":"cannot-play-audio-as-no-valid-encryption-package-i","errorCode":null,"errorMessage":"Cannot play audio as no valid encryption package is installed.\n- Install one of:\n  - sodium\n  - libsodium-wrappers\n  - @stablelib/xchacha20poly1305\n  - @noble/ciphers.\n- Use the generateDependencyReport() function for more information.\n","messagePattern":"Cannot play audio as no valid encryption package is installed\\.\n- Install one of:\n  - sodium\n  - libsodium-wrappers\n  - @stablelib/xchacha20poly1305\n  - @noble/ciphers\\.\n- Use the generateDependencyReport\\(\\) function for more information\\.\n","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"critical","filePath":"packages/voice/src/util/Secretbox.ts","lineNumber":92,"sourceCode":"\t\tcrypto_aead_xchacha20poly1305_ietf_encrypt(cipherText, additionalData, nonce, key) {\n\t\t\tconst crypto = new stablelib.XChaCha20Poly1305(key);\n\t\t\treturn crypto.seal(nonce, cipherText, additionalData);\n\t\t},\n\t}),\n\t'@noble/ciphers/chacha.js': (noble: any): Methods => ({\n\t\tcrypto_aead_xchacha20poly1305_ietf_decrypt(cipherText, additionalData, nonce, key) {\n\t\t\tconst chacha = noble.xchacha20poly1305(key, nonce, additionalData);\n\t\t\treturn chacha.decrypt(cipherText);\n\t\t},\n\t\tcrypto_aead_xchacha20poly1305_ietf_encrypt(plaintext, additionalData, nonce, key) {\n\t\t\tconst chacha = noble.xchacha20poly1305(key, nonce, additionalData);\n\t\t\treturn chacha.encrypt(plaintext);\n\t\t},\n\t}),\n} as const;\n\nconst fallbackError = () => {\n\tthrow new Error(\n\t\t`Cannot play audio as no valid encryption package is installed.\n- Install one of:\n  - sodium\n  - libsodium-wrappers\n  - @stablelib/xchacha20poly1305\n  - @noble/ciphers.\n- Use the generateDependencyReport() function for more information.\\n`,\n\t);\n};\n\nconst methods: Methods = {\n\tcrypto_aead_xchacha20poly1305_ietf_encrypt: fallbackError,\n\tcrypto_aead_xchacha20poly1305_ietf_decrypt: fallbackError,\n};\n\n// eslint-disable-next-line no-async-promise-executor\nexport const secretboxLoadPromise = new Promise<void>(async (resolve) => {\n\tfor (const libName of Object.keys(libs) as (keyof typeof libs)[]) {","sourceCodeStart":74,"sourceCodeEnd":110,"githubUrl":"https://github.com/discordjs/discord.js/blob/a81ed8a306d37fdc746e26a634b6a42164ba2c8c/packages/voice/src/util/Secretbox.ts#L74-L110","documentation":"Secretbox.ts lazily selects an encryption backend from the packages installed in your project (sodium, libsodium-wrappers, @stablelib/xchacha20poly1305, @noble/ciphers). If none of them are available at runtime, loading the secretbox module throws this Error telling you to install one and consult generateDependencyReport(). @discordjs/voice deliberately ships no crypto dependency, so this is a required optional peer dependency.","triggerScenarios":"Importing/starting any audio playback (@discordjs/voice loaded, playAudio/createAudioPacket path) in a project where none of the four supported encryption packages is installed — e.g. a bare `npm i @discordjs/voice` install, pnpm's strict node_modules hiding transitive deps, or monorepos where the dep is in another workspace.","commonSituations":"Fresh project setups following old tutorials; Docker images pruned with --omit=optional; pnpm/yarn PnP strict dependency resolution; CI environments missing the native sodium build toolchain so installation silently failed.","solutions":["Install a supported encryption package: npm i @noble/ciphers (pure JS) or npm i libsodium-wrappers.","Run generateDependencyReport() from @discordjs/voice to confirm which crypto package the library actually resolves.","Rebuild/reinstall if a native package (sodium) failed to compile — check node-gyp/python/make toolchain, or switch to the pure-JS @noble/ciphers.","If using pnpm/monorepos, add the crypto package as a direct dependency of the workspace that depends on @discordjs/voice."],"exampleFix":"// before\nimport { joinVoiceChannel } from '@discordjs/voice'; // throws: no encryption package\n// after\n// npm i @noble/ciphers\nimport { joinVoiceChannel } from '@discordjs/voice'; // resolves @noble/ciphers backend","handlingStrategy":"validation","validationCode":"// Run once at startup, before joining any channel:\nimport { generateDependencyReport } from '@discordjs/voice';\nconsole.log(generateDependencyReport());\n// Or programmatically fail fast:\nlet hasCrypto = false;\ntry { require.resolve('libsodium-wrappers'); hasCrypto = true; } catch {}\ntry { require.resolve('@noble/ciphers'); hasCrypto = true; } catch {}\nif (!hasCrypto) throw new Error('Install a crypto package for @discordjs/voice (e.g. npm i libsodium-wrappers)');","typeGuard":"null","tryCatchPattern":"null","preventionTips":["Always install a crypto package alongside @discordjs/voice (e.g. npm i @discordjs/voice libsodium-wrappers).","Run generateDependencyReport() in CI/startup to catch missing optional peers early.","In pnpm/monorepos, declare the crypto package as a direct dependency of the package importing @discordjs/voice.","Prefer pure-JS backends (@noble/ciphers, libsodium-wrappers) in Docker/CI where native build toolchains are absent."],"tags":["missing-dependency","encryption","audio","setup"],"backgroundTag":"missing-crypto-dependency","analyzedSha":"a81ed8a306d37fdc746e26a634b6a42164ba2c8c","analyzedAt":"2026-08-30T04:07:22.193Z","schemaVersion":2},"datasetVersion":"2026-08-30T08:17:16.595Z"}