stablyai/orca · error · Error
Invalid E2EE v2 authenticated response
Error message
Invalid E2EE v2 authenticated response
What it means
Thrown in the `awaiting-authenticated` state when the decrypted plaintext is a string but does not satisfy `isAuthenticated` — i.e. it is not a JSON object with exactly the keys `transcriptHashB64,type,v`, or `type !== 'e2ee_authenticated'`, or `v !== 2`, or the transcript hash does not equal the session's. Unlike an explicit `e2ee_error` rejection, this is a malformed or unexpected authenticated-shaped response.
Source
Thrown at mobile/src/transport/mobile-e2ee-v2-physical-channel.ts:111
}
if (this.state === 'awaiting-ready') {
this.acceptReady(raw)
return
}
const plaintext =
typeof raw === 'string'
? this.args.session.openText(raw)
: await this.openBinary(raw, generation)
if (generation !== this.generation || plaintext === null) {
return
}
if (this.state === 'awaiting-authenticated') {
if (typeof plaintext === 'string' && isAuthenticationRejection(plaintext)) {
throw new MobileE2EEAuthenticationError()
}
if (typeof plaintext !== 'string' || !this.isAuthenticated(plaintext)) {
throw new Error('Invalid E2EE v2 authenticated response')
}
this.state = 'ready'
this.args.onAuthenticated()
} else if (typeof plaintext === 'string') {
this.args.onText(plaintext)
} else {
this.args.onBinary(plaintext)
}
}
private acceptReady(raw: unknown): void {
if (typeof raw !== 'string') {
throw new Error('Expected plaintext E2EE v2 ready')
}
let ready: unknown
try {
ready = JSON.parse(raw)
} catch {View on GitHub (pinned to 1136503c6a)
Solutions
- Confirm desktop and mobile are on the same v2 e2ee contract version.
- Inspect the decrypted plaintext (via a debug hook) to see which `isAuthenticated` branch failed — extra keys, wrong type, or hash mismatch each point to a different cause.
- Treat as fatal for the link and tear down + retry the full handshake.
Example fix
// before
onError: (e) => log(e.message) // no recovery
// after
onError: (e) => {
if (e.message === 'Invalid E2EE v2 authenticated response') {
reportProtocolMismatchAndDisconnect(link)
} else { /* ... */ }
} Defensive patterns
Strategy: try-catch
Validate before calling
// No preventive call: the desktop sent a bad authenticated message. Validate after decrypt in a debug hook.
Type guard
function isAuthenticatedShape(msg: unknown): boolean {
if (typeof msg !== 'object' || msg === null) return false
const keys = Object.keys(msg).sort().join(',')
return keys === 'transcriptHashB64,type,v'
} Try / catch
channel.onError = (e) => { if (e.message === 'Invalid E2EE v2 authenticated response') { reportProtocolMismatch(link); link.close() } else { /* ... */ } } Prevention
- Version-negotiate e2ee v2 up front so schema drift is impossible.
- Tear down the link on this error — do not retry with the same peer.
- Log the decrypted plaintext (debug only) to identify which branch of isAuthenticated failed.
When it happens
Trigger: Desktop sent a non-rejection, non-authenticated plaintext during the auth window (e.g. a stray text frame); transcript-hash mismatch where neither side sent `e2ee_error`; a version-skewed desktop that uses a different authenticated schema or extra keys.
Common situations: Protocol version drift between mobile and desktop; a desktop bug that ships a mis-specified `e2ee_authenticated` message with extra fields; man-in-the-middle or corrupted frame that decrypts to plausible-but-wrong JSON.
Understand the failure class
- Authentication and authorization failures — expired tokens, bad credentials, and missing scopes.
Related errors
- E2EE v2 ready has not been accepted
- E2EE device authentication rejected
- Expected plaintext E2EE v2 ready
- Invalid E2EE v2 ready JSON
- Invalid E2EE v2 ready
AI-assisted analysis of stablyai/orca@1136503c6a (2026-08-12).
Data as JSON: /api/errors/ed45fe08241213d7.
Report an issue: GitHub.