{"record":{"id":"ad55f8d036c35b9c","repo":"remix-run/remix","slug":"cannot-specify-both-only-and-exclude-options","errorCode":null,"errorMessage":"Cannot specify both \"only\" and \"exclude\" options","messagePattern":"Cannot specify both \"only\" and \"exclude\" options","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/fetch-router/src/lib/route-helpers/resource.ts","lineNumber":62,"sourceCode":"      exclude?: ResourceMethod[]\n      only?: never\n    }\n)\n\n/**\n * Create a route map with standard CRUD routes for a singleton resource.\n *\n * @param base The base route pattern to use for the resource\n * @param options Options to configure the resource routes\n * @returns The route map with CRUD routes\n */\nexport function createResourceRoutes<base extends string, const options extends ResourceOptions>(\n  base: base | RoutePattern<base>,\n  options?: options,\n): BuildResourceMap<base, options> {\n  // Runtime validation\n  if (options?.only && options?.exclude) {\n    throw new Error('Cannot specify both \"only\" and \"exclude\" options')\n  }\n\n  // Resolve which methods to include\n  let only: readonly ResourceMethod[]\n  if (options?.only) {\n    only = options.only\n  } else if (options?.exclude) {\n    only = ResourceMethods.filter((m) => !options.exclude!.includes(m))\n  } else {\n    only = ResourceMethods\n  }\n\n  let newName = options?.names?.new ?? 'new'\n  let showName = options?.names?.show ?? 'show'\n  let createName = options?.names?.create ?? 'create'\n  let editName = options?.names?.edit ?? 'edit'\n  let updateName = options?.names?.update ?? 'update'\n  let destroyName = options?.names?.destroy ?? 'destroy'","sourceCodeStart":44,"sourceCodeEnd":80,"githubUrl":"https://github.com/remix-run/remix/blob/9696913134be3a4423513d2775f7b31d6917c049/packages/fetch-router/src/lib/route-helpers/resource.ts#L44-L80","documentation":"createResourceRoutes accepts either an `only` list (restrict to specific methods) or an `exclude` list (remove specific methods), but not both — they are contradictory filters. This runtime check rejects the combination immediately.","triggerScenarios":"createResourceRoutes('/posts', { only: ['list'], exclude: ['destroy'] }) — any call passing both options truthy.","commonSituations":"Merging option objects from config presets where a default only/exclude collides with a call-site override.","solutions":["Keep exactly one of only or exclude","When merging configs, delete the other key: { ...opts, exclude: undefined }","Prefer exclude for deny-lists and only for allow-lists — pick one strategy project-wide"],"exampleFix":"// before\ncreateResourceRoutes('/posts', { only: ['list','show'], exclude: ['destroy'] })\n// after\ncreateResourceRoutes('/posts', { only: ['list','show'] })","handlingStrategy":"validation","validationCode":"if (options?.only && options?.exclude) throw new Error('only and exclude are mutually exclusive')","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Pick one filtering strategy (only vs exclude) project-wide","Strip the conflicting key when merging option presets"],"tags":["fetch-router","routes","options"],"backgroundTag":"conflicting-options","analyzedSha":"9696913134be3a4423513d2775f7b31d6917c049","analyzedAt":"2026-08-27T19:55:01.024Z","schemaVersion":2},"datasetVersion":"2026-08-28T00:17:15.603Z"}