{"record":{"id":"80eacac9e5f0c5c7","repo":"remix-run/remix","slug":"optionpath-must-use-a-four-digit-year-of-2015-o","errorCode":null,"errorMessage":"${optionPath} must use a four-digit year of 2015 or higher","messagePattern":"(.+?) must use a four-digit year of 2015 or higher","errorType":"validation","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"packages/assets/src/lib/target.ts","lineNumber":162,"sourceCode":"  return Object.keys(normalizedTarget).length === 0 ? undefined : normalizedTarget\n}\n\nfunction normalizeScriptTargetVersion(value: unknown, optionPath: string): AssetTarget['es'] {\n  if (typeof value !== 'string') {\n    throw new TypeError(`${optionPath} must be a string`)\n  }\n\n  let normalizedValue = value.trim()\n  if (normalizedValue.length === 0) {\n    throw new TypeError(`${optionPath} must be a non-empty string`)\n  }\n\n  if (!/^\\d+$/.test(normalizedValue)) {\n    throw new TypeError(`${optionPath} must use a single numeric year like \"2020\"`)\n  }\n\n  if (!/^\\d{4}$/.test(normalizedValue) || Number(normalizedValue) < 2015) {\n    throw new TypeError(`${optionPath} must use a four-digit year of 2015 or higher`)\n  }\n\n  return `es${normalizedValue}`\n}\n\nfunction normalizeBrowserTargetVersion(value: unknown, optionPath: string): AssetTargetVersion {\n  if (typeof value !== 'string') {\n    throw new TypeError(`${optionPath} must be a string`)\n  }\n\n  if (value.trim().length === 0) {\n    throw new TypeError(`${optionPath} must be a non-empty string`)\n  }\n\n  if (!/^\\d+(\\.\\d+){0,2}$/.test(value)) {\n    throw new TypeError(`${optionPath} must use \"X\", \"X.Y\", or \"X.Y.Z\" version format`)\n  }\n","sourceCodeStart":144,"sourceCodeEnd":180,"githubUrl":"https://github.com/remix-run/remix/blob/9696913134be3a4423513d2775f7b31d6917c049/packages/assets/src/lib/target.ts#L144-L180","documentation":"Thrown when a script target version is numeric but not a valid four-digit year of at least 2015. The assets normalizer maps the year to an esbuild-style target like es2020, and esbuild's lowest supported ES target is es2015, so shorter numbers, future/non-4-digit numbers, or years below 2015 fail.","triggerScenarios":"`{ script: { es: '5' } }`, `{ script: { es: '20' } }`, `{ script: { es: '2014' } }`, or `{ script: { es: '302020' } }`.","commonSituations":"Using an ES level like '5' or '6' (as in tsconfig's ES5/ES6 naming) instead of a year; typos in the year; assuming any number is accepted because the earlier check only validates digits.","solutions":["Use a four-digit year >= 2015, e.g. '2020' or '2022'","For legacy ES5 output, pick '2015' as the oldest supported value and verify your toolchain","Validate year ranges in config UIs or scripts before submission"],"exampleFix":"// before\nlet target = { script: { es: '6' } }\n// after\nlet target = { script: { es: '2020' } }","handlingStrategy":"validation","validationCode":"let isValidEsYear = (value: string) => /^\\d{4}$/.test(value) && Number(value) >= 2015\nif (!isValidEsYear(esTarget)) throw new Error('script target must be a 4-digit year >= 2015')","typeGuard":"let isSupportedEsYear = (value: unknown): value is string =>\n  typeof value === 'string' && /^\\d{4}$/.test(value.trim()) && Number(value.trim()) >= 2015","tryCatchPattern":null,"preventionTips":["Use a shared constant like const ES_TARGET = '2020' in config","Avoid ES5/ES6-style level numbers; only years 2015+ are supported"],"tags":["config","validation","es-version"],"backgroundTag":"invalid-config-value","analyzedSha":"9696913134be3a4423513d2775f7b31d6917c049","analyzedAt":"2026-08-27T19:55:01.024Z","schemaVersion":2},"datasetVersion":"2026-08-28T00:17:15.603Z"}