Twelve kinds of failure, each with its own advice
complete() and json() throw a LodestoneError with one of these kind values. Open one to read the sentence explain(err, { product: 'MyApp', settingsHint: 'in Settings' }) gives a person.
authThe key was rejected (401). Another model on the same key would fail the same way.
“MyApp's AI provider isn't configured correctly right now. This isn't something you can fix. Try again shortly.”
rate_limitA limit was hit. detail.rateLimit says which: daily, per-minute, or a busy upstream.
“MyApp's shared AI budget for today is used up. Try again after midnight UTC, or add your own OpenRouter key in Settings.”
slowEvery attempt timed out inside the time budget.
“The AI is slow right now and did not answer in time. Try again in a minute.”
creditThe paid model needs credit that is not there (402).
“The AI account has no credit for the backup model. Add a little credit and try again.”
withdrawnThe provider no longer has the model (404).
“The AI models MyApp uses just changed on the provider's side. Try again in a few minutes.”
unavailableThe provider returned a server error.
“The AI provider is having issues right now, not MyApp. Try again in a few minutes.”
bad_outputAnswers came back but none was usable: empty, not JSON, or failed your check.
“The AI gave back something that couldn't be read. Try again; it usually works on a second attempt.”
budgetThe platform's spend limit stopped every paid option.
“MyApp's AI budget for now is used up, and the free models are busy. Try again later, or add your own OpenRouter key in Settings to keep going.”
abortedThe caller stopped the call by aborting its signal.
“Cancelled.”
not_configuredNo provider has a key.
“MyApp's AI isn't set up yet.”
throttledThis caller has used their allowance (rateLimit). detail.retryAfterMs says when to try again.
“You've made a lot of requests in a short time. Try again in about 20 minutes.”
otherAnything else. detail.providerMessage keeps the provider's own words.
“Something went wrong talking to the AI provider. Try again in a moment.”
The sentences are the library's own: this page calls explain() for each kind when it is built, so they cannot drift from the code.