{"record":{"id":"d6e1f03622b64f6a","repo":"remix-run/remix","slug":"optionpath-must-be-an-object","errorCode":null,"errorMessage":"${optionPath} must be an object","messagePattern":"(.+?) must be an object","errorType":"validation","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"packages/assets/src/lib/target.ts","lineNumber":94,"sourceCode":"\n  let lightningCssTargets: ResolvedStyleTarget = {}\n  for (let browserTargetName of browserTargetNames) {\n    let version = resolvedTarget[browserTargetName]\n    if (version == null) continue\n    lightningCssTargets[lightningCssTargetNameByBrowserTargetName[browserTargetName]] =\n      toLightningCssTargetVersion(version)\n  }\n\n  return lightningCssTargets\n}\n\nfunction normalizeScriptTargetObject(\n  target: AssetTarget | undefined,\n  optionPath: string,\n): NormalizedAssetTarget | undefined {\n  if (target == null) return undefined\n  if (!isPlainObject(target)) {\n    throw new TypeError(`${optionPath} must be an object`)\n  }\n\n  let normalizedTarget: NormalizedAssetTarget = {}\n\n  for (let [key, value] of Object.entries(target)) {\n    if (key === 'es') {\n      normalizedTarget.es = normalizeScriptTargetVersion(value, `${optionPath}.es`)\n      continue\n    }\n\n    if (!browserTargetNameSet.has(key)) {\n      throw new TypeError(`${optionPath}.${key} is not a supported target`)\n    }\n\n    normalizedTarget[key as BrowserTargetName] = normalizeBrowserTargetVersion(\n      value,\n      `${optionPath}.${key}`,\n    )","sourceCodeStart":76,"sourceCodeEnd":112,"githubUrl":"https://github.com/remix-run/remix/blob/9696913134be3a4423513d2775f7b31d6917c049/packages/assets/src/lib/target.ts#L76-L112","documentation":"The `script.target` option (e.g. `script: { target: ... }` or build.target) must be a plain object mapping target names to versions, not a string, array, or class instance. normalizeScriptTargetObject duck-checks with isPlainObject and throws otherwise.","triggerScenarios":"Passing `script: { target: 'es2022' }` (string), `target: ['es2022']` (array), or a class instance with target fields to the assets options.","commonSituations":"Porting esbuild/browserslist config where target is a string or array; spreading a config class instance; JSON configs typed loosely.","solutions":["Use the object form: { es: 2022 } or { chrome: '100' }","When accepting string config from users, convert 'es2022' to { es: 2022 } before passing","Ensure the value isn't a class instance — use a plain object literal"],"exampleFix":"// before\nscript: { target: 'es2022' }\n// after\nscript: { target: { es: 2022 } }","handlingStrategy":"type-guard","validationCode":"if (target != null && (typeof target !== 'object' || Array.isArray(target))) {\n  throw new Error('script.target must be an object like { es: 2022 }')\n}","typeGuard":"function isPlainTargetObject(v: unknown): v is Record<string, string | number | boolean> {\n  return v != null && typeof v === 'object' && !Array.isArray(v)\n    && Object.getPrototypeOf(v) === Object.prototype\n}","tryCatchPattern":null,"preventionTips":["Use object literals for target, not classes or strings","Convert esbuild-style string targets before passing"],"tags":["config","build","target","validation","assets"],"backgroundTag":"invalid-option-value","analyzedSha":"9696913134be3a4423513d2775f7b31d6917c049","analyzedAt":"2026-08-27T19:55:01.024Z","schemaVersion":2},"datasetVersion":"2026-08-28T00:17:15.603Z"}