paperclipai/paperclip · error

model pricing unavailable for ${model}

Error message

model pricing unavailable for ${model}

What it means

estimateModelCostNanodollars looks up per-token rates in its hardcoded RATES table and throws when the requested model string has no entry. Cost estimation is impossible without rates, so the library fails fast instead of returning a zero cost. Adding a model requires extending the RATES map.

Source

Thrown at packages/paperclip-runner/src/evals/model-pricing.ts:42

  "openrouter/qwen/qwen3.8-max-0902": { input: 2, cachedInput: 0.25, output: 6 },
  "openrouter/google/gemini-3.8-flash": { input: 0.75, cachedInput: 0.075, output: 3.75 },
  "openrouter/z-ai/glm-5.3": { input: 1.4, cachedInput: 0.14, output: 4.4 },
  "openrouter/deepseek/deepseek-v4-flash-0731": { input: 0.14, cachedInput: 0.028, output: 0.28 },
  "openrouter/openai/gpt-6-astra": { input: 10, cachedInput: 1, output: 50 },
});

export interface EstimatedModelCost {
  estimatedCostNanodollars: number;
  pricingVersion: typeof MODEL_PRICING_VERSION;
  ratesUsdPerMillionTokens: TokenRatesUsdPerMillion;
}

export function estimateModelCostNanodollars(
  model: string,
  usage: { inputTokens: number; cachedInputTokens: number; outputTokens: number },
): EstimatedModelCost {
  const rates = RATES[model];
  if (rates === undefined) throw new Error(`model pricing unavailable for ${model}`);
  const uncachedInput = Math.max(0, usage.inputTokens - usage.cachedInputTokens);
  const estimatedCostNanodollars = Math.round(
    uncachedInput * rates.input * 1_000
      + usage.cachedInputTokens * rates.cachedInput * 1_000
      + usage.outputTokens * rates.output * 1_000,
  );
  return { estimatedCostNanodollars, pricingVersion: MODEL_PRICING_VERSION, ratesUsdPerMillionTokens: { ...rates } };
}

View on GitHub (pinned to 01ad858492)

Solutions

  1. Add the missing model to the RATES map in packages/paperclip-runner/src/evals/model-pricing.ts with current input/cachedInput/output rates
  2. Normalize/alias the model string to a known key before calling (strip date suffixes, map aliases)
  3. Check the exact model string the usage object carries (log it) and align it with RATES keys
  4. Upgrade the package if a newer version added the model's pricing

Example fix

// before
const cost = estimateModelCostNanodollars(model, usage); // throws for unknown model
// after
const key = model.replace(/-\d{8}$/, '');
if (!(key in KNOWN_MODELS)) throw new Error(`add pricing for ${model} to RATES`);
const cost = estimateModelCostNanodollars(key, usage);
Defensive patterns

Strategy: validation

Validate before calling

if (!(model in RATES)) throw new Error(`no pricing for model ${model}; add to RATES`);

Type guard

function hasPricing(model: string): model is keyof typeof RATES {
  return model in RATES;
}

Try / catch

let cost: number;
try {
  cost = estimateModelCostNanodollars(model, usage);
} catch (err) {
  if (err instanceof Error && err.message.startsWith('model pricing unavailable')) {
    cost = 0; // or fall back to a token-based default
  } else throw err;
}

Prevention

When it happens

Trigger: Calling estimateModelCostNanodollars with a model name not present in the RATES lookup (new/unreleased model, aliased name, version-suffixed model ID, or typo).

Common situations: A provider released a new model before pricing was added; code passes a full model ID like 'claude-opus-4-1-20250805' while RATES keys by short name; renaming/moving models between providers.

Related errors


AI-assisted analysis of paperclipai/paperclip@01ad858492 (2026-09-02). Data as JSON: /api/errors/c03045c973efa729. Report an issue: GitHub.