{"record":{"id":"ee39b19ba8613342","repo":"GoogleCloudPlatform/microservices-demo","slug":"invalidcreditcard","errorCode":null,"errorMessage":"InvalidCreditCard","messagePattern":"InvalidCreditCard","errorType":"validation","errorClass":"InvalidCreditCard","httpStatus":null,"severity":"error","filePath":"src/paymentservice/charge.js","lineNumber":70,"sourceCode":"  }\n}\n\n/**\n * Verifies the credit card number and (pretend) charges the card.\n *\n * @param {*} request\n * @return transaction_id - a random uuid.\n */\nmodule.exports = function charge (request) {\n  const { amount, credit_card: creditCard } = request;\n  const cardNumber = creditCard.credit_card_number;\n  const cardInfo = cardValidator(cardNumber);\n  const {\n    card_type: cardType,\n    valid\n  } = cardInfo.getCardDetails();\n\n  if (!valid) { throw new InvalidCreditCard(); }\n\n  // Only VISA and mastercard is accepted, other card types (AMEX, dinersclub) will\n  // throw UnacceptedCreditCard error.\n  if (!(cardType === 'visa' || cardType === 'mastercard')) { throw new UnacceptedCreditCard(cardType); }\n\n  // Also validate expiration is > today.\n  const currentMonth = new Date().getMonth() + 1;\n  const currentYear = new Date().getFullYear();\n  const { credit_card_expiration_year: year, credit_card_expiration_month: month } = creditCard;\n  if ((currentYear * 12 + currentMonth) > (year * 12 + month)) { throw new ExpiredCreditCard(cardNumber.replace('-', ''), month, year); }\n\n  logger.info(`Transaction processed: ${cardType} ending ${cardNumber.substr(-4)} \\\n    Amount: ${amount.currency_code}${amount.units}.${amount.nanos}`);\n\n  return { transaction_id: uuidv4() };\n};\n","sourceCodeStart":52,"sourceCodeEnd":87,"githubUrl":"https://github.com/GoogleCloudPlatform/microservices-demo/blob/72ba613a05f7fcee51cf1d0badff401b6ae7074d/src/paymentservice/charge.js#L52-L87","documentation":"InvalidCreditCard is thrown by the checkout charge() function in src/paymentservice/charge.js when the simple-card-validator reports that the submitted credit card number does not pass its Luhn/format validity check (cardInfo.getCardDetails().valid is false). It signals a malformed or bogus card number in the ChargeRequest, not a payment network problem. The error extends CreditCardError with gRPC-style code 400 (Invalid Argument).","triggerScenarios":"Calling ChargeRequest via PlaceOrder with a credit_card_number that is not a syntactically valid card number (fails Luhn or length rules per simple-card-validator), e.g. a random digit string, a truncated number, or a placeholder like '0000-0000-0000-0000'.","commonSituations":"Test harnesses or load generators sending dummy card numbers; forms/skipped client-side validation passing raw user input; data migrations with corrupted card fields; unit tests forgetting that the demo checkout still validates card syntax.","solutions":["Send a Luhn-valid card number with correct length, e.g. '4012-8888-8888-1881' (VISA) or '5555-5555-5555-4444' (MasterCard)","Validate the card number client-side (or at the caller) with simple-card-validator before calling Charge","Check that the credit_card_number field is actually populated and not shifted/misaligned in your request construction","Remember the number must also be VISA/MasterCard to pass the next check"],"exampleFix":"// before\nawait paymentClient.Charge({ amount, credit_card: { credit_card_number: '1234-5678-9012-3456', ... } });\n// after\nawait paymentClient.Charge({ amount, credit_card: { credit_card_number: '4012-8888-8888-1881', ... } });","handlingStrategy":"validation","validationCode":"const cardValidator = require('simple-card-validator');\nfunction isChargeableCard(cardNumber) {\n  if (typeof cardNumber !== 'string' || !cardNumber.trim()) return false;\n  const details = cardValidator(cardNumber).getCardDetails();\n  return details.valid === true;\n}\nif (!isChargeableCard(req.credit_card.credit_card_number)) {\n  return res.status(400).json({ error: 'Invalid card number' });\n}","typeGuard":"function isValidCardNumber(v) {\n  return typeof v === 'string' && /^\\d{12,19}(-?\\d{4})+$/.test(v.replace(/-/g, '').length ? v : v) && require('simple-card-validator')(v).getCardDetails().valid === true;\n}","tryCatchPattern":"try {\n  const result = await paymentClient.Charge(chargeRequest);\n} catch (err) {\n  if (err.message === 'InvalidCreditCard' || /invalid/i.test(err.message)) {\n    return res.status(400).json({ error: 'Card number is not valid; please re-enter it.' });\n  }\n  throw err;\n}","preventionTips":["Validate card numbers with simple-card-validator on the client before calling Charge","Use known-good test card numbers (VISA 4012-8888-8888-1881, MC 5555-5555-5555-4444) in tests","Never send empty or placeholder card numbers to the payment service","Capture the card number field length/format at input time with Luhn checking"],"tags":["grpc","validation","payment","javascript"],"backgroundTag":"invalid-card-number","analyzedSha":"72ba613a05f7fcee51cf1d0badff401b6ae7074d","analyzedAt":"2026-09-02T01:15:09.673Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-09T06:17:21.866Z"}