unicity-aos/aos-ce · error

ingress pending read error for source_id

Error message

ingress pending read error for source_id '{source_id}', failing closed: {e}

What it means

The MCP broker's take_ingress_pending looks up pending ingress state for a source_id in KV. If the read errors (as opposed to returning Ok(None)), the broker fails closed — treating the pending state as absent/denying continuation — and logs this warning prefixed with the broker's log tag.

Solutions

  1. Check the {e} detail and restore KV availability; retry the execute flow once the store is healthy.
  2. Delete the corrupted pending record for that source_id so the next read is a clean miss.
  3. Verify the stored pending value matches the current broker schema (version upgrade drift).
  4. Expect fail-closed behavior: callers will see the flow as not-pending; re-initiate the ingress flow.

Example fix

// before
Err(e) => {
    log::warn(format!("{}: ingress pending read error for source_id '{source_id}', \
         failing closed: {e}", crate::profile::log_tag()));
    false
}
// after
// fix KV backend, or clear the bad key:
kv::delete(&pending_key(source_id)).ok();
Err(e) => {
    log::warn(format!("{}: ingress pending read error for source_id '{source_id}', \
         failing closed: {e}", crate::profile::log_tag()));
    false
}
Defensive patterns

Strategy: try-catch

Validate before calling

// before relying on pending state, probe the store
const reachable = await kv.ping();
if (!reachable) throw new Error('kv unavailable, execute flow will fail closed');

Try / catch

match kv::get(&pending_key) {
    Ok(Some(v)) => resume(v),
    Ok(None) => /* not pending */ false,
    Err(e) => { log::warn("ingress pending read error: {e}"); false } // fail closed
}

Prevention

When it happens

Trigger: KV read of the ingress-pending entry for source_id returns Err inside take_ingress_pending — storage backend unavailable, decode failure of the stored value, or an I/O error on the pending record.

Common situations: KV store restart or network partition during an MCP execute flow; corrupted/unexpected bytes at the pending key after a schema change; source_id reused across broker restarts with stale records.

Understand the failure class

Background: Database query failed: Internal Server Error 500s wrapping SQL, Prisma, and connection failures — what to check first — this error's family across 16 libraries.

Related errors


AI-assisted analysis of unicity-aos/aos-ce@f6f22024fb (2026-09-13). Data as JSON: /api/errors/be0740d532a83390. Report an issue: GitHub.

Appendix: source

Thrown at crates/aos-mcp-broker/src/execute.rs:420

/// is one re-usable stale marker, never a denied legitimate grant).
pub(crate) fn take_ingress_pending(source_id: &str) -> bool {
    let Some(key) = ingress_pending_key(source_id) else {
        return false;
    };
    match kv::get_bytes_opt(&key) {
        Ok(Some(_)) => {
            if let Err(e) = kv::delete(&key) {
                log::warn(format!(
                    "{}: failed to clear ingress pending marker for source_id \
                     '{source_id}': {e}",
                    crate::profile::log_tag()
                ));
            }
            true
        }
        Ok(None) => false,
        Err(e) => {
            log::warn(format!(
                "{}: ingress pending read error for source_id '{source_id}', \
                 failing closed: {e}",
                crate::profile::log_tag()
            ));
            false
        }
    }
}

/// KV key marking an outstanding capsule-grant consent prompt for a
/// `(principal, capsule_id)` pair. KV is per-principal-scoped by the kernel,
/// so the capsule id alone disambiguates within the keyspace — the principal
/// is implicit in the storage scope, not the key suffix. Same empty-suffix
/// guard as [`ingress_pending_key`]: an empty `capsule_id` must never resolve
/// to a routable key (it would collapse to the bare prefix and let one marker
/// dedup every grant prompt for the principal). The `principal` is accepted
/// for symmetry with the call sites and to keep the dedup key intent explicit,
/// but is NOT stamped into the suffix (the KV scope already carries it).

View on GitHub (pinned to f6f22024fb)