Skip to content

python3 not found inside pipelines or sh -c, and the pipeline returns exit 0 #1881

Description

@NicolaiHerforth

Ran into this building a sandbox integration on @rivet-dev/agentos-core 0.2.15. python3 works on its own but vanishes as soon as it's inside a subshell.

import { AgentOs } from "@rivet-dev/agentos-core";

const vm = await AgentOs.create({});

for (const cmd of [
  `python3 -c "print('hi')"`,
  `python3 -c "print('hi')" | head -n 1`,
  `sh -c "python3 -c 'print(1)'"`,
  `echo hi | head -n 1`,
]) {
  const r = await vm.exec(cmd);
  console.log(`${cmd}\n  exitCode=${r.exitCode}  stdout=${JSON.stringify(r.stdout)}  stderr=${JSON.stringify(r.stderr)}\n`);
}

await vm.dispose();
python3 -c "print('hi')"
  exitCode=0  stdout="hi\n"  stderr=""

python3 -c "print('hi')" | head -n 1
  exitCode=0  stdout=""  stderr="error: command not found: python3\n"

sh -c "python3 -c 'print(1)'"
  exitCode=127  stdout=""  stderr="error: command not found: python3\n"

echo hi | head -n 1
  exitCode=0  stdout="hi\n"  stderr=""

I think there are two things here.

The first is that python3 isn't resolvable inside a subshell. Since anything with a pipe gets wrapped in sh -c, pipelines hit the same wall. Plain coreutils are fine (echo hi | head works), so it looks specific to the kernel-stub commands — /bin/python3 is a 32-byte #!/bin/sh + # kernel command stub file, which I assume is meant to be intercepted by name before anything actually execs it, and the interception doesn't reach into the child shell.

The second one is what actually bit us: the pipeline returns exitCode: 0 even though the command wasn't found. The sh -c case gets it right and returns 127. We check exit codes to decide whether a command worked, so a 0 with empty stdout reads as "ran fine, no output" rather than "never ran".

Same shape with registry commands — rg from @agentos-software/ripgrep 0.3.3 works standalone but gives failed to execute command 'rg': Permission denied (os error 2) inside sh -c.

Possibly related to #1877 since that's in the same area, though python3 is a runtime rather than a published command package, so it might be separate.

Happy to test a patch if it's useful.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions