{"record":{"id":"ac4e804ac7e87535","repo":"pear-devs/pear-desktop","slug":"media-element-expected","errorCode":null,"errorMessage":"Media element expected!","messagePattern":"Media element expected!","errorType":"validation","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"src/plugins/crossfade/fader.ts","lineNumber":91,"sourceCode":"  private active: boolean = false;\n  private fade: VolumeFade | undefined;\n\n  /**\n   * VolumeFader Constructor\n   *\n   * @param media {HTMLMediaElement} - audio or video element to be controlled\n   * @param options {Object} - an object with optional settings\n   * @throws {TypeError} if options.initialVolume or options.fadeDuration are invalid\n   *\n   */\n  constructor(media: HTMLMediaElement, options: VolumeFaderOptions) {\n    // Passed media element of correct type?\n    if (media instanceof HTMLMediaElement) {\n      // Save reference to media element\n      this.media = media;\n    } else {\n      // Abort and throw an exception\n      throw new TypeError('Media element expected!');\n    }\n\n    // Make sure options is an object\n    options = options || {};\n\n    // Log function passed?\n    if (typeof options.logger === 'function') {\n      // Set log function to the one specified\n      this.logger = options.logger;\n    } else {\n      // Set log function explicitly to false\n      this.logger = null;\n    }\n\n    // Linear volume fading?\n    if (options.fadeScaling === 'linear') {\n      // Pass levels unchanged\n      this.scale = {","sourceCodeStart":73,"sourceCodeEnd":109,"githubUrl":"https://github.com/pear-devs/pear-desktop/blob/1e2aac5706c870c93ed74ba8727ae8390d3b0fa5/src/plugins/crossfade/fader.ts#L73-L109","documentation":"The VolumeFader constructor requires a real media element because it drives fades by writing to HTMLMediaElement.volume. Anything that is not an instanceof HTMLMediaElement (audio or video tag) is rejected with this TypeError immediately at construction.","triggerScenarios":"Calling `new VolumeFader(document.querySelector('.audio'))` when the selector matched nothing (null) or matched a non-media element (a <div> or <source>); passing a jQuery wrapper, an element from another document/realm where instanceof fails; constructing before the DOM element exists.","commonSituations":"Running the script before the audio element is mounted (null from querySelector); grabbing the wrong node in a shadow DOM or iframe; passing a wrapped/extended element from another window context so the instanceof check fails; refactors that changed the tag from <audio> to a custom element.","solutions":["Guard construction: `const el = document.querySelector('audio'); if (el instanceof HTMLMediaElement) new VolumeFader(el, ...)`","Initialize the fader after the element exists (DOMContentLoaded, component mount, or player-ready callback)","If dealing with iframes/multiple realms, use a duck-typed check ('play' in el && 'volume' in el) instead of instanceof","Verify the selector/tag: the element must literally be an <audio> or <video> element"],"exampleFix":"// before\nconst fader = new VolumeFader(document.querySelector('#player'));\n\n// after\nconst el = document.querySelector('#player');\nif (!(el instanceof HTMLMediaElement)) throw new Error('player element not ready');\nconst fader = new VolumeFader(el);","handlingStrategy":"type-guard","validationCode":"const el = document.querySelector<HTMLAudioElement>('audio');\nif (!el) { /* element not mounted yet; init later */ }","typeGuard":"const isMediaElement = (el: Element | null): el is HTMLMediaElement =>\n  el instanceof HTMLMediaElement;","tryCatchPattern":"try { fader = new VolumeFader(el); } catch (e) { if (e instanceof TypeError && /Media element/.test(e.message)) { retry after mount } else throw e; }","preventionTips":["Construct the fader only after the <audio>/<video> element exists (mount/ready callback)","Use querySelector<HTMLAudioElement>('audio') so TypeScript enforces the tag","Never pass wrapped elements (jQuery, custom wrappers) directly"],"tags":["crossfade","dom","validation","typeerror","media-element"],"backgroundTag":"invalid-dom-element-argument","analyzedSha":"1e2aac5706c870c93ed74ba8727ae8390d3b0fa5","analyzedAt":"2026-08-27T20:01:08.614Z","schemaVersion":2},"datasetVersion":"2026-08-28T00:17:15.603Z"}