can1357/oh-my-pi · error · AIError.ProviderResponseError

Devin Connect frame length ${len} exceeds ${MAX_CONNECT_FRAM

Error message

Devin Connect frame length ${len} exceeds ${MAX_CONNECT_FRAME_PAYLOAD}-byte cap

What it means

This ProviderResponseError is thrown while parsing the Devin Connect binary stream in streamDevin. The wire protocol prefixes each frame with a 1-byte flag and a 4-byte big-endian length; before reading a frame body the parser checks the declared length against MAX_CONNECT_FRAME_PAYLOAD. A length over the cap means the byte stream is no longer a valid Connect framing sequence (desync or a non-Connect response), so continuing would allocate unbounded memory or misparse everything downstream.

Source

Thrown at packages/ai/src/providers/devin.ts:247

			const reader = body.getReader();
			let pending = Buffer.alloc(0);

			for (;;) {
				const { done, value } = await reader.read();
				if (value && value.length > 0) {
					// Steady state drains fully per chunk; view the fresh reader chunk
					// instead of copying it through Buffer.concat (see aws-eventstream.ts).
					pending =
						pending.length === 0
							? Buffer.from(value.buffer, value.byteOffset, value.byteLength)
							: Buffer.concat([pending, value]);
				}

				while (pending.length >= 5) {
					const flag = pending[0];
					const len = pending.readUInt32BE(1);
					if (len > MAX_CONNECT_FRAME_PAYLOAD) {
						throw new AIError.ProviderResponseError(
							`Devin Connect frame length ${len} exceeds ${MAX_CONNECT_FRAME_PAYLOAD}-byte cap`,
							{ provider: model.provider, kind: "envelope" },
						);
					}
					if (pending.length < 5 + len) break;
					const payload = pending.subarray(5, 5 + len);
					pending = pending.subarray(5 + len);

					if (flag & CONNECT_END_STREAM_FLAG) {
						const trailerBytes = flag & CONNECT_COMPRESSED_FLAG ? gunzipSync(payload) : payload;
						const trailerError = readConnectTrailerError(trailerBytes.toString("utf8").trim());
						if (trailerError) {
							// #4218: these rejections carry no HTTP error body, so the raw
							// trailer is the only server-side evidence. Log it with the
							// request shape before classification discards it.
							logger.warn("devin: stream rejected via Connect trailer", {
								model: model.id,
								code: trailerError.code,

View on GitHub (pinned to 9690622007)

Solutions

  1. Verify the Devin base URL points at the Connect streaming endpoint, not a plain HTTP/JSON route
  2. Retry once — transient proxy corruption can desync framing; check whether the error recurs on every request
  3. Capture the model/provider config and update the pi-ai package if Devin changed its Connect framing protocol
  4. Check any corporate proxy/TLS-inspecting middlebox for body rewriting

Example fix

// before: pointing baseUrl at a JSON REST endpoint
baseUrl: "https://api.devin.ai/v1"
// after: use the Connect streaming endpoint for streamDevin
baseUrl: "https://connect.devin.ai" // per Devin Connect docs
Defensive patterns

Strategy: validation

Validate before calling

// Confirm the endpoint speaks Connect framing before streaming:
const res = await fetch(baseUrl + "/devin.Connect/Stream", { method: "POST" });
const ct = res.headers.get("content-type") ?? "";
if (!ct.includes("connect") && !ct.includes("proto")) {
  throw new Error(`Expected Connect stream, got content-type ${ct}`);
}

Type guard

function isConnectFrameHeader(buf: Uint8Array): boolean {
  if (buf.length < 5) return false;
  const len = new DataView(buf.buffer, buf.byteOffset, buf.byteLength).getUint32(1, false);
  return len > 0 && len <= 4 * 1024 * 1024; // within sane frame cap
}

Try / catch

try {
  await streamDevin(model, context, options);
} catch (err) {
  if (err instanceof AIError.ProviderResponseError && err.message.includes("-byte cap")) {
    // framing desync: surface the provider config and retry once or report a protocol bug
    logger.error("Devin Connect framing desync", { model: model.id, cause: err });
  } else throw err;
}

Prevention

When it happens

Trigger: A streamed response from the Devin endpoint whose first five bytes decode to a frame length larger than MAX_CONNECT_FRAME_PAYLOAD — e.g. the server returned an HTML error page, JSON, or compressed/unframed data that the parser misread as a length header, or protocol/version drift changed the framing.

Common situations: Devin gateway changes or proxies returning HTML/JSON error bodies over HTTP 200; base URL pointing at a non-Connect endpoint; Devin server-side protocol changes; corrupt intermediate proxy mangling the byte stream.

Related errors


AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31). Data as JSON: /api/errors/e6bfd6dd552caeaa. Report an issue: GitHub.