stablyai/orca · error · Error

Invalid reset response from host

Error message

Invalid reset response from host

What it means

First of four sibling guards in decodeResetResult(): rejects the host's reset-credit response if value is null/undefined, not an object, or an array. The Codex reset-credit flow needs a plain object envelope ({scope, snapshot, status/outcome, ...}); anything else is treated as a malformed wire payload and aborts decoding before deeper field checks run.

Source

Thrown at mobile/src/components/codex-reset-credit.ts:160

function scopesEqual(
  left: CodexResetCreditExpectedScope,
  right: CodexResetCreditExpectedScope
): boolean {
  return (
    left.target.runtime === right.target.runtime &&
    left.target.wslDistro === right.target.wslDistro &&
    left.accountId === right.accountId &&
    left.accountRevision === right.accountRevision &&
    left.offerRevision === right.offerRevision
  )
}

function decodeResetResult(
  value: unknown,
  expectedScope: CodexResetCreditExpectedScope
): CodexResetCreditRpcResult {
  if (!value || typeof value !== 'object' || Array.isArray(value)) {
    throw new Error('Invalid reset response from host')
  }
  const result = value as Record<string, unknown>
  const scope = CodexResetCreditExpectedScopeSchema.safeParse(result.scope)
  if (!scope.success || !scopesEqual(scope.data, expectedScope)) {
    throw new Error('Invalid reset response from host')
  }
  const snapshot = decodeAccountsSnapshot(result.snapshot)
  if (result.status === 'rejectedBeforeProvider') {
    const reason = result.reason
    if (
      result.retryDisposition !== 'discardAttempt' ||
      result.outcome !== undefined ||
      (reason !== 'targetChanged' &&
        reason !== 'accountChanged' &&
        reason !== 'accountRevisionChanged' &&
        reason !== 'accountRuntimeChanged' &&
        reason !== 'offerUnavailable' &&
        reason !== 'offerChanged')

View on GitHub (pinned to 1136503c6a)

Solutions

  1. Inspect the actual RPC result value the host returned for consumeCodexResetCredit.
  2. Fix the host handler to always return the documented result object shape.
  3. If integrating a stub, return an object with the expected keys, not a primitive/array.
  4. Reproduce by logging `value` before the guard.

Example fix

// before
if (!value || typeof value !== 'object' || Array.isArray(value)) {
  throw new Error('Invalid reset response from host')
}

// after — name the shape problem
if (!value || typeof value !== 'object' || Array.isArray(value)) {
  throw new Error(`Invalid reset response from host: expected object, got ${Array.isArray(value) ? 'array' : typeof value}`)
}
Defensive patterns

Strategy: validation

Validate before calling

function isPlainObject(v: unknown): v is Record<string, unknown> {
  return typeof v === 'object' && v !== null && !Array.isArray(v)
}
if (!isPlainObject(value)) {
  throw new Error(`Invalid reset response from host: expected object, got ${Array.isArray(value) ? 'array' : typeof value}`)
}

Type guard

function isResetResultEnvelope(v: unknown): v is Record<string, unknown> {
  return typeof v === 'object' && v !== null && !Array.isArray(v)
}

Try / catch

try {
  const decoded = decodeResetResult(raw, expectedScope)
} catch (err) {
  // Treat as a malformed wire response; re-fetch snapshot and abort the reset UX
  setResetError('Reset response was malformed. Refresh and retry.')
}

Prevention

When it happens

Trigger: accounts.consumeCodexResetCredit returns null, undefined, a primitive (string/number), or an array instead of the expected result object.

Common situations: Host bug returning the wrong shape, a relay/proxy mangling the response, a version skew where the host returns a bare error string on an unhandled path, or a mock/stub returning [] during testing.

Related errors


AI-assisted analysis of stablyai/orca@1136503c6a (2026-08-12). Data as JSON: /api/errors/088c504ea9e86158. Report an issue: GitHub.