{"id":"a05f55d8bf18e048","repo":"webpack/webpack","slug":"request-should-be-a-string-or-object-with-loader-a","errorCode":null,"errorMessage":"request should be a string or object with loader and options (${JSON.stringify(value)})","messagePattern":"request should be a string or object with loader and options \\((.+?)\\)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"lib/loaders/LoaderRunner.js","lineNumber":161,"sourceCode":"\t\treturn escapeHash(this.path) + escapeHash(this.query) + this.fragment;\n\t}\n\n\t/**\n\t * @param {LoaderItemInput} value loader request or descriptor\n\t */\n\tset request(value) {\n\t\tif (typeof value === \"string\") {\n\t\t\tconst { path, query, fragment } = parseResource(value);\n\t\t\tthis.path = path;\n\t\t\tthis.query = query;\n\t\t\tthis.fragment = fragment;\n\t\t\tthis.options = undefined;\n\t\t\tthis.ident = undefined;\n\t\t\treturn;\n\t\t}\n\n\t\tif (!value.loader) {\n\t\t\tthrow new Error(\n\t\t\t\t`request should be a string or object with loader and options (${JSON.stringify(\n\t\t\t\t\tvalue\n\t\t\t\t)})`\n\t\t\t);\n\t\t}\n\n\t\tconst { loader: path, fragment, type, options, ident } = value;\n\t\tthis.path = path;\n\t\tthis.fragment = fragment || \"\";\n\t\tthis.type = type;\n\t\tthis.options = options;\n\t\tthis.ident = ident;\n\n\t\tif (options === null || options === undefined) {\n\t\t\tthis.query = \"\";\n\t\t} else if (typeof options === \"string\") {\n\t\t\tthis.query = `?${options}`;\n\t\t} else if (ident) {","sourceCodeStart":143,"sourceCodeEnd":179,"githubUrl":"https://github.com/webpack/webpack/blob/318421ea8ac81371f5171236a6efb63675576528/lib/loaders/LoaderRunner.js#L143-L179","documentation":"Inside the vendored loader-runner, a LoaderObject's request setter accepts either a string (parsed into path/query/fragment) or a descriptor object. The descriptor path requires a `loader` string property (the loader's resolved path); the setter throws when value is an object lacking `loader`. The thrown message stringifies the bad value for diagnosis. This is hit when webpack/NormalModule resolves and assigns loader descriptors from module.rules.","triggerScenarios":"A rule's `use`/`loader` entry resolves to an object without a `loader` key, e.g. { options: {...} } with no loader, or a malformed loader descriptor returned by a custom resolve hook. Also reachable if a plugin taps NormalModuleFactory and emits a bad loader descriptor.","commonSituations":"Typos in module.rules (writing { options: {} } instead of { loader: 'babel-loader', options: {} }). A plugin or custom resolver that constructs loader descriptors dynamically and forgets the loader field. Corrupted/empty loader string after path resolution.","solutions":["Inspect the offending rule/use entry and ensure each object has a `loader` string (e.g. { loader: 'babel-loader', options: {...} }).","If using a function in module.rules.use, verify it returns { loader, options } and never an options-only object.","Check any custom NormalModuleFactory tap that mutates or injects loader descriptors."],"exampleFix":"// before\nmodule.exports = {\n  module: { rules: [{ test: /\\.js$/, use: [{ options: { presets: ['@babel/env'] } }] }] }\n};\n// after\nmodule.exports = {\n  module: { rules: [{ test: /\\.js$/, use: [{ loader: 'babel-loader', options: { presets: ['@babel/env'] } }] }] }\n};","handlingStrategy":"type-guard","validationCode":"// Validate module.rules.use entries before passing to webpack\nfunction normalizeRules(rules) {\n  for (const rule of rules) {\n    const uses = Array.isArray(rule.use) ? rule.use : (rule.use ? [rule.use] : []);\n    for (const u of uses) {\n      if (u && typeof u === 'object' && !('loader' in u) && !u.loader) {\n        throw new Error('Rule use entry is missing a \"loader\" field: ' + JSON.stringify(u));\n      }\n    }\n  }\n}","typeGuard":"/** @typedef {{ loader: string, options?: object }} LoaderDescriptor */\n/** @param {unknown} u\n * @returns {u is LoaderDescriptor} */\nfunction isLoaderDescriptor(u) {\n  return !!u && typeof u === 'object' && typeof u.loader === 'string';\n}","tryCatchPattern":null,"preventionTips":["Always include `loader` in every object form of module.rules.use.","If a use callback returns an object, type-check its return value against the loader-descriptor shape."],"tags":["loaders","module-rules","config"],"analyzedSha":"318421ea8ac81371f5171236a6efb63675576528","analyzedAt":"2026-08-03T19:39:56.731Z","schemaVersion":2}