{"record":{"id":"dc3c8262ceb383bb","repo":"gchq/CyberChef","slug":"invalid-file-type-dc3c82","errorCode":null,"errorMessage":"Invalid file type","messagePattern":"Invalid file type","errorType":"exception","errorClass":"OperationError","httpStatus":null,"severity":"error","filePath":"src/core/operations/PlayMedia.mjs","lineNumber":89,"sourceCode":"        }\n\n        return input;\n    }\n\n    /**\n     * Displays an audio or video element that may be able to play the media\n     * file.\n     *\n     * @param {byteArray} data Data containing an audio or video file.\n     * @returns {string} Markup to display a media player.\n     */\n    async present(data) {\n        if (!data.length) return \"\";\n\n        const types = detectFileType(data);\n        const matches = /^audio|video/.exec(types[0].mime);\n        if (!matches) {\n            throw new OperationError(\"Invalid file type\");\n        }\n        const dataURI = `data:${types[0].mime};base64,${toBase64(data)}`;\n        const element = matches[0];\n\n        let html = `<${element} src='${dataURI}' type='${types[0].mime}' controls>`;\n        html += \"<p>Unsupported media type.</p>\";\n        html += `</${element}>`;\n        return html;\n    }\n}\n\nexport default PlayMedia;\n","sourceCodeStart":71,"sourceCodeEnd":102,"githubUrl":"https://github.com/gchq/CyberChef/blob/4290ea753912378913b1f3f54e0fc5720afeda5d/src/core/operations/PlayMedia.mjs#L71-L102","documentation":"Play Media's present() re-detects the file type with detectFileType(data) and requires types[0].mime to start with 'audio' or 'video' before building the <audio>/<video> element. This is a second guard after run() already validated with isType; it can fire when detection returns a non-media type first (detectFileType returns an ordered list and present() only inspects index 0) or when the data passed to present differs from what run validated.","triggerScenarios":"detectFileType returns a list whose first entry is a non-media type even though isType earlier matched an audio/video type deeper in the list; present() is called with empty/changed data; a file that triggers ambiguous signatures where the top match is not media.","commonSituations":"A file with a magic sequence shared by a non-media format that sorts first in detection; chaining ops that alter the byte array between run and present; very short or ambiguous inputs.","solutions":["Ensure the data reaching present() is the same media bytes validated by run().","If the file has an ambiguous signature, re-encode it to a clean, unambiguous container.","Confirm the file is genuinely audio/video and not mis-detected due to truncation.","Treat both Play Media errors identically: the bytes are not recognised media."],"exampleFix":null,"handlingStrategy":"validation","validationCode":"import { detectFileType } from \"../lib/FileType.mjs\";\nconst types = detectFileType(data);\nif (!types.length || !/^audio|video/.test(types[0].mime)) {\n  throw new Error(\"Top detected type is not audio/video\");\n}","typeGuard":"function topTypeIsMedia(data) {\n  const types = detectFileType(data);\n  return types.length > 0 && /^audio|video/.test(types[0].mime);\n}","tryCatchPattern":"try {\n  return await playMedia.present(data);\n} catch (e) {\n  if (e.message === \"Invalid file type\") {\n    // detection disagrees with run(); re-encode to an unambiguous container\n  }\n  throw e;\n}","preventionTips":["Do not mutate the byte array between run and present.","Prefer unambiguous media containers.","Treat both Play Media errors as 'not recognised media'."],"tags":["media","file-type","presentation","audio","video"],"backgroundTag":null,"analyzedSha":"4290ea753912378913b1f3f54e0fc5720afeda5d","analyzedAt":"2026-08-13T06:05:50.210Z","schemaVersion":2},"datasetVersion":"2026-08-13T09:17:06.757Z"}