medusajs/medusa · error · MedusaError
Product option value with id "${valueId}" was not found for
Error message
Product option value with id "${valueId}" was not found for option with id "${optionId}" What it means
Thrown by retrieveProductOptionValue when the query for a product option value filtered by both valueId and optionId returns nothing. It enforces that the value actually belongs to the given option, so a mismatch reads the same as a missing record.
Source
Thrown at packages/medusa/src/api/admin/product-options/[id]/values/[value_id]/route.ts:32
const retrieveProductOptionValue = async (
req: AuthenticatedMedusaRequest<unknown, unknown>,
fields?: string[]
): Promise<HttpTypes.AdminProductOptionValue> => {
// Ensure the value belongs to the option
const { value_id: valueId, id: optionId } = req.params
const query = req.scope.resolve(ContainerRegistrationKeys.QUERY)
const {
data: [product_option_value],
} = await query.graph({
entity: "product_option_value",
filters: { id: valueId, option_id: optionId },
fields: fields ?? ["id"],
})
if (!product_option_value) {
throw new MedusaError(
MedusaError.Types.NOT_FOUND,
`Product option value with id "${valueId}" was not found for option with id "${optionId}"`
)
}
return product_option_value
}
/**
* @since 2.16.0
*/
export const GET = async (
req: AuthenticatedMedusaRequest<{}, HttpTypes.SelectParams>,
res: MedusaResponse<HttpTypes.AdminProductOptionValueResponse>
) => {
const product_option_value = await retrieveProductOptionValue(
req,
req.queryConfig.fieldsView on GitHub (pinned to 5e06e544a2)
Solutions
- List the option's values (GET /admin/product-options/:id/values) and confirm the pairing before mutating
- Rebuild the value/option id mapping in your client state from a fresh fetch
- On 404, re-fetch the option and reselect the correct value id
Example fix
// before
await sdk.client.fetch(`/admin/product-options/${optionId}/values/${valueId}`, { method: "DELETE" })
// after
const { values } = await fetchOptionValues(optionId)
if (!values.some((v) => v.id === valueId)) {
throw new Error(`Value ${valueId} is not on option ${optionId}`)
}
await sdk.client.fetch(`/admin/product-options/${optionId}/values/${valueId}`, { method: "DELETE" }) Defensive patterns
Strategy: validation
Validate before calling
const { values } = await getOptionValues(optionId)
if (!values.some((v) => v.id === valueId)) throw new Error(`Value ${valueId} not on option ${optionId}`) Type guard
const belongsToOption = (v: { id: string; option_id?: string }, optionId: string) =>
v.option_id === optionId || !!v.option_id === false && valuesOf(optionId).includes(v.id) Try / catch
try {
await deleteOptionValue(optionId, valueId)
} catch (e: any) {
if (e.statusCode === 404) { await refetchOption(optionId); return }
throw e
} Prevention
- Keep option/value pairs as one unit in client state
- Re-fetch the option before mutations in stale UIs
- Never copy value ids across options during imports
When it happens
Trigger: Calling GET/POST/DELETE on /admin/product-options/:id/values/:value_id where the value id exists but belongs to a different option, or either id is wrong/deleted.
Common situations: Frontends keeping option and value ids in separate state and pairing them incorrectly after reordering, copying value ids between options during data imports, or stale ids after option regeneration.
Understand the failure class
Background: 'Could not be found', 'does not exist', 'not found in database': the resource-not-found family when an ID, slug, key, or URI lookup comes back empty — this error's family across 20 libraries.
Related errors
- Invite with id: ${id} was not found
- Price list with id: ${id} was not found
- Product category with id: ${req.params.id} was not found
- Product tag with id "${req.params.id}" not found
- Product type with id "${req.params.id}" not found
AI-assisted analysis of medusajs/medusa@5e06e544a2 (2026-08-27).
Data as JSON: /api/errors/ee9357eb57ab6139.
Report an issue: GitHub.