Skip to content

Inferlet stdout writes before first .await don't surface as Event.Stdout on the WS path #360

Description

@shsym

TL;DR. Hi! While instrumenting an inferlet for cache-hit/miss tracing, we noticed that println! calls in the inferlet's main before the first .await never reach a pie-client listener as Event.Stdout, while the same println! calls after the first .await come through fine. Same wasm, same engine — the difference is just where the print happens in the async flow. pie run --stdout (in-process) shows all prints correctly, so the bytes do leave the wasm; something between the runtime and the WS client appears to swallow the early ones. Wanted to flag it so y'all can decide if it's a known limitation or worth a tweak.

Repro

#[inferlet::main]
async fn main(input: Input) -> Result<String> {
    println!(\"[before-await] this NEVER reaches the WS client\");
    let model = Model::load(runtime::models().first().unwrap())?;  // first .await is inside this chain
    println!(\"[after-await] this DOES reach the WS client\");
    Ok(String::new())
}

Client side:

from pie_client import PieClient, Event
c = PieClient(\"ws://127.0.0.1:8080\")
await c.connect(); await c.authenticate(\"u\", None)
p = await c.launch_process(\"my-inferlet@0.1.0\", input={})
events = []
while True:
    e, v = await p.recv()
    events.append((e, v))
    if e in (Event.Return, Event.Error): break
# events contains the `[after-await]` Stdout but NOT the `[before-await]` one.

pie run --stdout --path my-inferlet.wasm --manifest Pie.toml --input '{}' prints both lines, so the wasm is emitting them.

Expected

Every println! produced by the inferlet surfaces as exactly one Event.Stdout, regardless of where it lands relative to the first .await. (Or, if early writes are intentionally captured-elsewhere, a docstring note on #[inferlet::main] or the LogStream setup would save a debugging session.)

What we tried

  • std::io::stdout().flush() after the early println! — no effect on the WS path; still shows up in pie run --stdout only.
  • Checked the Python client's orphan_events path — appears correct (events would be buffered until the process queue is created); seems to point upstream of the websocket.
  • Confirmed the wasm contains the [before-await] string (strings ...wasm finds it).

We worked around it by appending an APC-status tag to the inferlet's return value, which is the official Event.Return payload, so this is not blocking us — but the early-stdout drop made tracing harder than it needed to be, so flagging.

Environment

  • pie 0.3.0 (main)
  • portable driver, Qwen3-0.6B, Linux x86_64 inside Docker

Happy to share the full repro inferlet if useful!

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions