jackwener/OpenCLI · error · CommandExecutionError
Product mismatch: expected ${productId}, ${observed}
Error message
Product mismatch: expected ${productId}, ${observed} What it means
CommandExecutionError thrown when the in-page evaluation returns reason 'PRODUCT_MISMATCH': the product ID parsed from the URL path (/vp/products/(\d+)) does not match the --product-id argument the user passed. The library guards against clicking add-to-cart on the wrong product.
Source
Thrown at clis/coupang/add-to-cart.js:131
const productId = rawProductId
? requireProductIdArg(rawProductId, 'product-id')
: requireProductIdArg(kwargs.url, '--url');
const targetUrl = canonicalizeProductUrl(kwargs.url, productId);
const finalUrl = targetUrl || canonicalizeProductUrl('', productId);
await page.goto(finalUrl).catch((error) => {
throw new CommandExecutionError(`coupang add-to-cart navigation failed: ${error?.message || error}`);
});
const result = await page.evaluate(buildAddToCartEvaluate(productId)).catch((error) => {
throw new CommandExecutionError(`coupang add-to-cart evaluation failed: ${error?.message || error}`);
});
const loginHints = result?.loginHints ?? {};
if (loginHints.hasLoginLink && !loginHints.hasMyCoupang) {
throw new AuthRequiredError('coupang.com', 'Please log into Coupang in Chrome and retry.');
}
const actualProductId = normalizeProductId(result?.currentProductId || productId);
if (result?.reason === 'PRODUCT_MISMATCH') {
const observed = actualProductId ? `got ${actualProductId}` : 'no product id observed';
throw new CommandExecutionError(`Product mismatch: expected ${productId}, ${observed}`);
}
if (result?.reason === 'OPTION_REQUIRED') {
throw new CommandExecutionError('This product requires option selection and is not supported in v1.');
}
if (result?.reason === 'ADD_TO_CART_BUTTON_NOT_FOUND') {
throw new CommandExecutionError('Could not find an add-to-cart button on the product page.');
}
if (!result?.ok) {
throw new CommandExecutionError('Failed to confirm add-to-cart success.');
}
return [{
ok: true,
product_id: actualProductId || productId,
url: finalUrl,
message: 'Added to cart',
}];
},
});View on GitHub (pinned to 49907e53dc)
Solutions
- Compare the expected vs observed product IDs in the message and re-run with the correct --product-id
- Omit --product-id and pass only the canonical product --url so the ID is derived from the destination
- Check whether Coupang redirects your URL to a different product and use the final URL's ID
- If the product was merged/delisted, look up the new product ID on Coupang
Example fix
// before coupang add-to-cart --product-id 11111 --url https://www.coupang.com/vp/products/22222 // after coupang add-to-cart --url https://www.coupang.com/vp/products/22222
Defensive patterns
Strategy: validation
Validate before calling
const urlId = (url.match(/\/vp\/products\/(\d+)/) || [])[1];
if (productId && urlId && productId !== urlId) {
throw new Error(`product-id ${productId} does not match url id ${urlId}`);
} Type guard
function idsMatch(productId, url) {
const m = typeof url === 'string' && url.match(/\/vp\/products\/(\d+)/);
return !productId || !m || String(productId) === m[1];
} Try / catch
try {
await addToCart(page, productId);
} catch (err) {
if (/Product mismatch/.test(err.message)) {
const [, expected, observed] = err.message.match(/expected (\d+), (.*)/) || [];
console.error(`Re-run with observed id: ${observed}`);
return;
}
throw err;
} Prevention
- Derive the product id from the URL rather than passing both independently
- Resolve redirects to the final canonical URL before extracting the ID
- Re-lookup product IDs after Coupang merges/delists products
When it happens
Trigger: Calling add-to-cart with a product-id that differs from the ID of the page actually loaded — e.g. Coupang redirected to a canonical/alternate product page, or the caller passed a stale/mistyped ID.
Common situations: Product URL redirects to a different (merged) product; passing the URL of one product with the ID of another; Coupang product ID changed after re-listing; copy-paste error in automation scripts.
Related errors
- Either --product-id or --url is required
- query cannot be empty
- Unsupported --filter
- INVALID_ARGUMENT
- INVALID_ARGUMENT
AI-assisted analysis of jackwener/OpenCLI@49907e53dc (2026-08-29).
Data as JSON: /api/errors/f6ec03ce80f45683.
Report an issue: GitHub.