{"record":{"id":"031a3d434ed4a0de","repo":"bilibili/flv.js","slug":"custom-seektype-specified-in-config-but-invalid-cu","errorCode":null,"errorMessage":"Custom seekType specified in config but invalid customSeekHandler!","messagePattern":"Custom seekType specified in config but invalid customSeekHandler!","errorType":"validation","errorClass":"InvalidArgumentException","httpStatus":null,"severity":"error","filePath":"src/io/io-controller.js","lineNumber":231,"sourceCode":"    }\n\n    get loaderType() {\n        return this._loader.type;\n    }\n\n    _selectSeekHandler() {\n        let config = this._config;\n\n        if (config.seekType === 'range') {\n            this._seekHandler = new RangeSeekHandler(this._config.rangeLoadZeroStart);\n        } else if (config.seekType === 'param') {\n            let paramStart = config.seekParamStart || 'bstart';\n            let paramEnd = config.seekParamEnd || 'bend';\n\n            this._seekHandler = new ParamSeekHandler(paramStart, paramEnd);\n        } else if (config.seekType === 'custom') {\n            if (typeof config.customSeekHandler !== 'function') {\n                throw new InvalidArgumentException('Custom seekType specified in config but invalid customSeekHandler!');\n            }\n            this._seekHandler = new config.customSeekHandler();\n        } else {\n            throw new InvalidArgumentException(`Invalid seekType in config: ${config.seekType}`);\n        }\n    }\n\n    _selectLoader() {\n        if (this._config.customLoader != null) {\n            this._loaderClass = this._config.customLoader;\n        } else if (this._isWebSocketURL) {\n            this._loaderClass = WebSocketLoader;\n        } else if (FetchStreamLoader.isSupported()) {\n            this._loaderClass = FetchStreamLoader;\n        } else if (MozChunkedLoader.isSupported()) {\n            this._loaderClass = MozChunkedLoader;\n        } else if (RangeLoader.isSupported()) {\n            this._loaderClass = RangeLoader;","sourceCodeStart":213,"sourceCodeEnd":249,"githubUrl":"https://github.com/bilibili/flv.js/blob/42343088f22619cf014a057b3878fe3d320016a6/src/io/io-controller.js#L213-L249","documentation":"IOController._selectSeekHandler validates config.seekType; when seekType === 'custom' it requires config.customSeekHandler to be a constructor function. This InvalidArgumentException is thrown when seekType is 'custom' but customSeekHandler is missing, not a function (e.g. an object or undefined), or would fail to construct.","triggerScenarios":"Creating an IOController (directly or via player/feature config) with { seekType: 'custom' } while customSeekHandler is undefined, null, a plain object, or a non-constructor value such as an arrow-function-returning-object used incorrectly.","commonSituations":"Copy-pasting a config that sets seekType:'custom' without supplying the handler, passing a class from another module that tree-shaking removed, typos in the config key (customSeekhandler), or passing an instance instead of the class itself.","solutions":["Pass a valid constructor: customSeekHandler: MySeekHandler (the class itself, not an instance)","Implement the custom handler as a class/function compatible with SeekHandler (getConfig, resolveSeekRequest, etc.)","Verify the config key spelling: customSeekHandler","If you don't need custom seeking, set seekType to 'range' or 'param' instead"],"exampleFix":"// before\nconst controller = new IOController(fetchLoader, { seekType: 'custom', customSeekHandler: new MySeekHandler() }, extraData);\n// after\nconst controller = new IOController(fetchLoader, { seekType: 'custom', customSeekHandler: MySeekHandler }, extraData); // pass the class, not an instance","handlingStrategy":"validation","validationCode":"if (config.seekType === 'custom' && typeof config.customSeekHandler !== 'function') {\n  throw new TypeError('customSeekHandler must be a constructor function');\n}","typeGuard":"const hasValidCustomSeekHandler = (c) =>\n  c.seekType !== 'custom' || typeof c.customSeekHandler === 'function';","tryCatchPattern":"try {\n  const controller = new IOController(loaderClass, config, extraData);\n} catch (e) {\n  if (e instanceof InvalidArgumentException && /customSeekHandler/.test(e.message)) {\n    config.seekType = 'range';\n  }\n}","preventionTips":["Pass the handler class itself, never an instance","Keep the customSeekHandler config key spelled exactly (camelCase)","Unit-test config objects that use seekType:'custom'","Prefer built-in 'range'/'param' seek types unless custom behavior is required"],"tags":["config","seek","invalid-argument"],"backgroundTag":"invalid-config-value","analyzedSha":"42343088f22619cf014a057b3878fe3d320016a6","analyzedAt":"2026-09-01T00:27:28.147Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T05:18:18.240Z"}