{"record":{"id":"8569aec1903c2dc1","repo":"jackwener/OpenCLI","slug":"no-cost-model-is-defined-for-action-operation","errorCode":null,"errorMessage":"No cost model is defined for action \"${operation}\"","messagePattern":"No cost model is defined for action \"(.+?)\"","errorType":"validation","errorClass":"ArgumentError","httpStatus":null,"severity":"error","filePath":"clis/midjourney/capabilities.js","lineNumber":313,"sourceCode":"  if (!ACTION_CHOICES.includes(operation)) {\n    throw new ArgumentError(`operation must be one of: ${ACTION_CHOICES.join(', ')}`);\n  }\n  if (operation === 'open-editor' || operation === 'cancel') return 0;\n  if (operation === 'rerun' && sourceIsVideo) {\n    if (!['sd', 'hd'].includes(videoResolution)) throw new ArgumentError('--video-resolution must be sd or hd');\n    if (![1, 2, 4].includes(batchSize)) throw new ArgumentError('--batch-size must be 1, 2, or 4');\n    return GPU_COST_MINUTES[`video${videoResolution === 'hd' ? 'Hd' : 'Sd'}${batchSize}`];\n  }\n  if (sourceUsesOmni && ['rerun', 'vary-subtle', 'vary-strong'].includes(operation)) {\n    return GPU_COST_MINUTES.omni;\n  }\n  if (Object.prototype.hasOwnProperty.call(ACTION_COSTS, operation)) return ACTION_COSTS[operation];\n  if (['animate-low', 'animate-high', 'loop-low', 'loop-high', 'extend-low', 'extend-high'].includes(operation)) {\n    if (!['sd', 'hd'].includes(videoResolution)) throw new ArgumentError('--video-resolution must be sd or hd');\n    if (![1, 2, 4].includes(batchSize)) throw new ArgumentError('--batch-size must be 1, 2, or 4');\n    return GPU_COST_MINUTES[`video${videoResolution === 'hd' ? 'Hd' : 'Sd'}${batchSize}`];\n  }\n  throw new ArgumentError(`No cost model is defined for action \"${operation}\"`);\n}\n\nexport function assertActionPlan(account, operation, { videoResolution = 'sd' } = {}) {\n  const capabilities = planCapabilities(account);\n  if (videoResolution === 'hd' && !capabilities.canHdVideo\n    && ['animate-low', 'animate-high', 'loop-low', 'loop-high', 'extend-low', 'extend-high'].includes(operation)) {\n    throw new ArgumentError(`${capabilities.plan || 'current'} plan does not support HD video; use --video-resolution sd`);\n  }\n  return capabilities;\n}\n\nexport function buildEffectivePrompt(prompt, plan, args, remoteReferences = {}) {\n  let result = String(prompt || '').trim();\n  const imageUrls = remoteReferences.image || [];\n  if (imageUrls.length) result = `${imageUrls.join(' ')} ${result}`.trim();\n\n  const additions = [];\n  if (!promptParamValue(result, ['v', 'version']) && !promptParamValue(result, ['niji']) && args.model && args.model !== 'auto') {","sourceCodeStart":295,"sourceCodeEnd":331,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/midjourney/capabilities.js#L295-L331","documentation":"estimateAction ends with a catch-all: if the operation is not free (open-editor/cancel), not a video rerun, not omni-related, not in ACTION_COSTS, and not one of the six video actions, no cost model exists and this ArgumentError is thrown.","triggerScenarios":"estimateAction with an operation that is in ACTION_CHOICES but has no cost branch — typically after ACTION_CHOICES was extended without adding a matching ACTION_COSTS entry or cost branch.","commonSituations":"Adding a new action to ACTION_CHOICES only (partial feature wiring); refactoring that removed an ACTION_COSTS key; callers passing internal action names that are intentionally unsupported for estimation.","solutions":["Add an entry for the operation to ACTION_COSTS (or a cost branch) in capabilities.js","Use an operation that already has a cost model (listed in the error)","Align ACTION_CHOICES and cost tables in the same change/PR","Add a unit test asserting every ACTION_CHOICES entry has a resolvable cost"],"exampleFix":"// before\n// ACTION_CHOICES includes 'upscale-x' but ACTION_COSTS does not\nestimateAction('upscale-x', opts);\n// after\nconst ACTION_COSTS = { ..., 'upscale-x': 2 }; // define the cost\nestimateAction('upscale-x', opts);","handlingStrategy":"validation","validationCode":"import { ACTION_CHOICES, ACTION_COSTS } from './clis/midjourney/capabilities.js';\nif (!Object.prototype.hasOwnProperty.call(ACTION_COSTS, operation)) {\n  throw new Error(`no cost model for \"${operation}\"; add it to ACTION_COSTS or use a supported action`);\n}\nconst minutes = estimateAction(operation, opts);","typeGuard":"function hasCostModel(op) {\n  return typeof op === 'string' && Object.prototype.hasOwnProperty.call(ACTION_COSTS, op);\n}","tryCatchPattern":"try {\n  const minutes = estimateAction(operation, opts);\n} catch (err) {\n  if (err instanceof ArgumentError && /No cost model is defined/.test(err.message)) {\n    console.error(`Action \"${operation}\" lacks a cost model; pick a supported action or update ACTION_COSTS`);\n  } else throw err;\n}","preventionTips":["Every new ACTION_CHOICES entry must get an ACTION_COSTS key or explicit cost branch in the same PR","Add a test asserting every action yields a numeric cost","Don't expose internally-pending action names to users until costed","Grep capabilities.js for the operation name before wiring a new subcommand"],"tags":["argument-error","cost-model","configuration","midjourney"],"backgroundTag":"missing-cost-model","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}