Insurgently

Refusal codes

Every code a Hub error can carry, and what to do about each.

For people building on Model Hub.

The Hub never falls back silently. Every refusal or failure is an error with a code, a message written for the user, and details. Show the message; branch on the code.

try {
  await hub.complete('mine.summarize', messages);
} catch (e) {
  const err = e as Error & { code?: string };
  if (err.code === 'aborted') return;
  new Notice(err.message);
}

Refused and failed calls are written to the ledger at a cost of zero, except reply-cut-off: that call did use tokens, and its row keeps the cost.

Limits#

CodeWhenWhat to do
over-ceilingThe call could cost more than a per-call limit. Checked before sending.Show the message. Send less, or lower maxOutputTokens.
over-budgetA monthly budget on the role or its tier is used up.Show the message. The user raises the limit or waits.
unpriced-modelThe model has no listed price, so a limit can't be checked.Show the message.

Models and providers#

CodeWhenWhat to do
no-modelsThe role's tier has no models set.Show the message; it points the user to the Hub's settings.
unknown-providerA model's provider isn't set up in the Hub.Show the message.
unknown-modelThe model isn't one the Hub knows.Show the message.
provider-unavailableThe provider has no key, or its server isn't answering.Show the message.
provider-errorThe provider returned an error. details.retryable says whether trying again may help.Retry if retryable; otherwise show the message.
capability-missingThe model can't do what the call needs: tools, structured output, web search, images, embeddings. details.missing lists them.Show the message. Declare needs so this is caught on every model.
reply-cut-offThe model stopped at the cap before writing any text, usually because it spent every token reasoning. details carry the usage, the cap, the reply cap and the thinking budget. If the role had another candidate, it was tried first.Show the message. Set the role's reasoning to off or a lower level, or raise maxOutputTokens.
model-not-allowedThe call named a tier, model or list for one run, and the role doesn't allow it; or an embed spec named a model the role hasn't used.Set allowAnyModel on roles where the user picks a model, or pinnedModels on an embedding role whose indexes keep their model.
fingerprint-mismatchexpectFingerprint didn't match what the call would make (v2:, before sending) or made (v1, after). details has expected, actual and formVersion.The index needs its own spec, or a re-embed. Price one with describeEmbedding.

Your own calls#

CodeWhenWhat to do
invalid-role-nameA role isn't named namespace.name in lowercase.Fix the name.
role-takenThe namespace belongs to another plugin, or you tried to change a role you don't own.Use your own namespace.
unknown-roleNo plugin has registered the role.Register before calling.
unknown-tierdeleteTier named a tier that doesn't exist.Check tiers() first.
invalid-tier-nameA tier's name is taken, empty, over 40 characters or a built-in tier's.Choose another name.
invalid-skillA registered skill has no or a bad SKILL.md, a path outside its folder, a repeated name, or mode: always.Fix the skill.
skill-takenThe skill's name belongs to another plugin or to the Hub.Choose another name.
invalid-requestThe request is malformed.Fix the call.
abortedYour signal stopped the call.Nothing; the user stopped it.

Tools#

Tool refusals and failures are written to the tool-call log, not the ledger.

CodeWhenWhat to do
tool-unknowncallTool named a tool no plugin has registered.Check tools() first.
tool-name-takenregisterTools used a namespace that belongs to another plugin.Use your own namespace.
tool-invalid-inputThe arguments don't match the tool's schema, or can't be written as JSON. details.problem says what is wrong.Fix the call.
tool-deniedThe user's setting is Deny, the run's tool list leaves the tool out, the user declined, or nobody answered in 2 minutes. details.reason is policy, user or no-answer.Show the message. Don't retry at once.
tool-failedThe handler threw, its plugin was unloaded during the call, the plugin offers no undo, or an undo failed.Show the message.
tool-timeoutThe handler ran over 60 seconds.Show the message.
run-budgetA call would take the run past its budgetUsd.Show the message, or start a run with more room.

aborted also applies to tools: your signal stopped the call, or its run ended.

Edits#

CodeWhenWhat to do
edit-no-matchpreviewEdits: an op couldn't be placed (not found, found in several places without replaceAll, overlapping another op, or empty), or a note is missing. The message names each op; details.failures lists them. Nothing was previewed.Add context to the op's oldText, or use replaceAll.
edit-staleapplyEdits: a range changed since the preview, so nothing was written; or the preview expired. undoEdit: the text the edit wrote has changed since, so the note was kept.Preview again; for undo, tell the user the note was kept as it is.
Package
@insurgently/model-hub-api
Plugin id
model-hub
Needs
Obsidian 1.13.1, desktop
License
MIT