From the Mohio team

Why a Missing AI Fallback Should Be a Build Error

Ron Smith 5 min read

You wouldn't query a database without handling the case where it returns nothing. So why are you calling an AI model without handling the case where it isn't sure?

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

Ron Smith

Founder of Mohio and Particular LLC. Building the first AI-native programming language from Mooresville, NC.

Mohio founder

Questions about this topic

What is an AI fallback in Mohio?
An AI fallback is a required code path that fires when an AI decision cannot be made confidently. Mohio has two: not confident fires when the model's confidence is below your threshold, and on.failure fires when the AI service is unavailable or errors. Both are explicit paths you define, not crash conditions.
How does Mohio enforce confidence thresholds?
The confidence above N declaration in an ai.decide block sets a minimum floor. If the model returns a confidence score below that number, the not confident path fires automatically. You set the threshold based on what the decision is worth. The language enforces it at runtime.
Does Mohio work with multiple AI providers?
Yes. Mohio's AI primitives are provider-agnostic. The model provider is configured via environment variables, not in your application code. Switching providers doesn't require changing any of your .mho files.
What happens to an ai.decide block if the API is down?
The on.failure block fires. You define the fallback behavior, typically a specific HTTP status code and message that tells the upstream system to retry or escalate. The application does not crash and the failure mode is explicit and visible in the code.
Does Mohio log AI decisions automatically?
Yes, when you include ai.audit to log_name in an ai.decide block. Every decision is logged with its inputs, the model's output, and the confidence score. In financial and healthcare sector profiles, this audit logging is required and enforced automatically by the sector declaration.
← All articles

Try it yourself

The compiler is open source. Clone the repo, run your first .mho file, and see what changes.