Hacktoberfest 2026:メンテナが10月に向けて印を付けた、オープンで初心者向けの issue。 Hacktoberfest の issue を見る

ReadableStream cannot be returned through a forwarded stub

オープン
#228 コメント 0 件 リアクション 0 件 担当者 0 名 GitHub で見る

メンテナーはふだん 5 日以内に返信

まだ誰も着手していません。

評価

難易度
3/5
見積もり時間
1〜2日
初心者へのやさしさ
68/100
issue の種類
バグ
明瞭さ
おおむね明確
活発さ
静か
技術スタック
javascript, typescript

調査の方向性

RpcPayload.ensureDeepCopied() と getHookForReadableStream から始め、次に issue の 2 セッション broker の例を再現します。childStub.dup() を介して返された ReadableStream が owned-payload エラーなしで呼び出し元に到達し、direct-session の動作は変わらないことを確認します。

索引モデルが issue の本文から書いたものです。

説明

A ReadableStream returned by an RPC method works when the caller holds a direct session to the target. It throws when the call is forwarded through an intermediate session, such as when a broker returns a dup of a stub it holds to a third party.

  1. Create a session between a broker and a child. The child has a method that returns a ReadableStream.
  2. Create a second session between a caller and the broker. The broker exposes a method that returns childStub.dup().
  3. From the caller, resolve that stub and call the stream-returning method on it.

Expected: the caller receives a ReadableStream, the same as it would on a direct session.

Actual: Error: owned payload shouldn't contain raw ReadableStreams.

Cause: RpcPayload.ensureDeepCopied() sets source to "owned" after the first hop. getHookForReadableStream handles "params" and "return" and throws on anything else. Regular stubs forward across the same two sessions without error, so only streams hit this.

import { newMessagePortRpcSession, RpcTarget } from "capnweb";

class Child extends RpcTarget {
  async ping() { return "pong"; }
  async tail() {
    let i = 0;
    return new ReadableStream({
      pull(c) { if (i >= 3) return c.close(); c.enqueue(new Uint8Array([i++])); }
    });
  }
}

class Broker extends RpcTarget {
  constructor(child) { super(); this.child = child; }
  async resolveChild() { return this.child.dup(); }
}

const childChan = new MessageChannel();
newMessagePortRpcSession(childChan.port2, new Child());
const childFromBroker = newMessagePortRpcSession(childChan.port1);

const brokerChan = new MessageChannel();
newMessagePortRpcSession(brokerChan.port2, new Broker(childFromBroker));
const broker = newMessagePortRpcSession(brokerChan.port1);

const child = await broker.resolveChild();
console.log(await child.ping()); // "pong"
await child.tail();              // throws

Tested on capnweb 0.10.0. The same error string is present in 0.8.0.

Workaround: return an RpcTarget with a next() method instead of the stream, and rebuild the stream on the caller side.

主要言語
TypeScript
スター
4k
フォーク
150
平均マージ
3日 12時間
マージ済み PR(30日)
2

環境構築

はじめの一歩

  1. issue を最後まで読み、次にプロジェクトのコントリビューションガイドを読みます。
  2. 着手することを issue にコメントします — 二人が同じ作業をするのを防げます。
  3. リポジトリをフォークし、ブランチを切って変更します。
  4. issue 番号を参照したプルリクエストを送ります。

cloudflare/capnweb のほかの issue

cloudflare/capnweb の issue をすべて見る

似ている issue

TypeScript の issue をもっと見る

新しい issue をメールで受け取る

初心者向けの GitHub issue を短くまとめたダイジェスト。