You handle database failures. You handle network timeouts. Why does your AI code assume the model will always be confident and available?
Here is how most AI-integrated code looks in the wild:
const response = await openai.chat.completions.create({
model: "gpt-4",
messages: [{ role: "user", content: buildPrompt(transaction) }]
});
const decision = response.choices[0].message.content;
// use the decision
That code has no plan for the API being down. It has no plan for the model returning something unexpected. It has no plan for the model being technically responsive but genuinely uncertain about the answer.
It just uses the decision.
You would not write database code like this:
const result = await db.query("SELECT * FROM members WHERE id = ?", [id]);
// just use result, what could go wrong
You would handle the null case. You would handle the database being unreachable. You would handle the query returning something you did not expect. You have been doing this for years. It is not optional. It is just how you write code that touches data.
AI calls are not more reliable than database calls. They are less reliable. They have more failure modes. And in the applications being built today, they are making decisions about money, health, access, and safety.
The fallback is not a nice-to-have. It is the other half of the feature.
What AI failure actually looks like
There are three ways an AI decision can fail, and they need different handling.
The API fails. The model service is down, times out, or returns a rate limit error. Your application is now making a decision without the AI you built it around. Something has to happen next, and "crash" is not an answer.
The model responds but is not confident. The model gives you an answer, but it is genuinely uncertain. A fraud detection model returning 0.62 confidence on a $40,000 wire transfer is a different situation than returning 0.96. Most AI code treats these identically. They are not identical.
The model responds with something wrong. Wrong format, wrong type, unexpected structure. Your downstream code breaks in a way that has nothing to do with the AI's reasoning and everything to do with missing validation on what came back.
Each of these needs an explicit path. Not error handling added after the fact. An explicit path, designed at the same time as the happy path, because the unhappy paths are just as real.
How Mohio handles it
In Mohio, AI decisions are a native language construct. The compiler knows they exist and knows what they need.
ai.decide isFraudulent returns boolean
confidence above 0.85
weigh
transaction.amount
transaction.velocity_score
transaction.device_fingerprint
member.transaction_history
ai.audit to fraud_audit_log
not confident
give back 202 "Referred to manual review"
on.failure
give back 503 "Fraud check unavailable"
ai.decide: done
Three things are happening here that most AI code skips entirely.
confidence above 0.85 sets the floor. The model has to be at least 85% confident or the not confident path fires. You set the number based on what the decision is worth. The language enforces it.
not confident is the explicit path for the model being uncertain. You decide what happens. In this case the transaction goes to a human reviewer. That is not a crash. It is a designed outcome that your business already needs to handle.
on.failure is the explicit path for the API not responding. The application does not break. It returns a 503 and the upstream system knows to retry. Your on-call engineer does not get paged because the AI vendor had an outage.
The ai.audit line means every decision gets logged: the inputs, the output, the confidence score, and which path fired. You can always see what happened and why.
The thing people push back on
"My AI calls are working fine. I don't need this."
They are working fine until they are not. AI services have outages. Model behavior changes between versions. Confidence distributions that were calibrated on last month's data may not hold on this month's patterns.
The discipline is not for when things are working. It is for when they stop. And in a production system making real decisions about real people, "the AI was unavailable" is not a complete answer.
There is also a less obvious benefit. When you write not confident -> give back 202 "Referred to manual review", you are documenting a business decision in code. When does this system escalate to a human? Right there. When the next developer reads it, or when you read it six months from now, the behavior is visible. It is not in a Confluence page that nobody updates. It is in the code.
The broader point
We write careful code around databases because we learned, the hard way, that databases fail and data matters. The lesson took a while and some of the learning was expensive.
We are going to learn the same lesson about AI. Some of those lessons are going to be expensive too.
Mohio's position is simple: if you are using AI to make a decision, the compiler should require you to handle the case where the AI cannot make that decision. Not as a library. Not as a best-practices guide. As a build requirement.
The fallback is not extra. It is the job.
Mohio is an AI-native programming language in active development. The language and base runtime are open source. Start building at mohio.io