stablyai/orca · error

Simulator stream must use http or https.

Error message

Simulator stream must use http or https.

What it means

normalizeStreamUrl rejects any URL whose protocol is not http: or https:. MjpegFrameStream only speaks HTTP (it dispatches via node:http/https), so a ws://, file://, or other scheme would break the request constructor.

Source

Thrown at src/main/emulator/mjpeg-frame-stream.ts:18

import { request as httpRequest, type ClientRequest, type IncomingMessage } from 'node:http'
import { request as httpsRequest } from 'node:https'
import { extractJpegFrames } from './mjpeg-frame-parser'

const RECONNECT_DELAY_MS = 1_000
const REQUEST_TIMEOUT_MS = 10_000
const MAX_FPS = 30
const MIN_FRAME_INTERVAL_MS = Math.floor(1_000 / MAX_FPS)

export type MjpegFrameStreamCallbacks = {
  onError: (message: string) => void
  onFrame: (frame: Buffer<ArrayBufferLike>) => void
}

function normalizeStreamUrl(streamUrl: string, streamKey?: string): URL {
  const url = new URL(streamUrl)
  if (url.protocol !== 'http:' && url.protocol !== 'https:') {
    throw new Error('Simulator stream must use http or https.')
  }
  if (!url.pathname.endsWith('/stream.mjpeg')) {
    throw new Error('Simulator stream must target stream.mjpeg.')
  }
  url.searchParams.set('raw', '1')
  if (streamKey) {
    url.searchParams.set('_orca', streamKey)
  }
  return url
}

function requestForUrl(url: URL, response: (res: IncomingMessage) => void): ClientRequest {
  return (url.protocol === 'https:' ? httpsRequest : httpRequest)(
    url,
    {
      headers: {
        Accept: 'application/octet-stream, image/jpeg'
      },

View on GitHub (pinned to 1136503c6a)

Solutions

  1. Pass the `streamUrl` field of EmulatorSessionInfo, not `wsUrl`.
  2. Confirm parseServeSimDetachedSession populated streamUrl from an http(s) source.
  3. Normalize/validate the URL scheme before constructing the stream.

Example fix

// before
new MjpegFrameStream(session.wsUrl, cb) // ws://...

// after
new MjpegFrameStream(session.streamUrl, cb) // http://.../stream.mjpeg
Defensive patterns

Strategy: validation

Validate before calling

const u = new URL(streamUrl)
if (u.protocol !== 'http:' && u.protocol !== 'https:') { throw new Error('pass session.streamUrl (http(s))') }

Type guard

function isStreamProtocolError(e: unknown): boolean {
  return e instanceof Error && /must use http or https/.test(e.message)
}

Try / catch

try { new MjpegFrameStream(url, cb) }
catch (e) { if (isStreamProtocolError(e)) { url = session.streamUrl; new MjpegFrameStream(url, cb) } else throw e }

Prevention

When it happens

Trigger: Constructing `new MjpegFrameStream(streamUrl, ...)` where `new URL(streamUrl).protocol` is anything except http/https (mjpeg-frame-stream.ts:16-18).

Common situations: Passing the session's wsUrl (ws://...) where streamUrl is expected; a copy-paste of the websocket endpoint; a serve-sim output schema change returning a non-http URL field.

Related errors


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