slimtoolkit/slim · critical · call.error

ptrace.App.collect.wpid

ptrace.App.collect.wpid

Error message

wpid is -1

What it means

In ptrace.App.collect, the waitpid-based collection loop receives wpid == -1, meaning waitpid failed to report any stopped tracee child. The code marks the app failed (AppFailed) and pushes this structured error onto errorCh. A TODO notes this branch may leave the sensor stuck, i.e. the wait loop exited without a valid child event.

Source

Thrown at pkg/monitor/ptrace/ptrace.go:738

			app.StateCh <- AppFailed
			app.collectorDoneCh <- 2
			return
		}

		logger.Tracef("wait4 -> wpid=%v wstatus=%v (Exited=%v Signaled=%v Signal='%v' Stopped=%v StopSignalInfo=%s TrapCause=%s)",
			wpid,
			ws,
			ws.Exited(),
			ws.Signaled(),
			ws.Signal(),
			ws.Stopped(),
			StopSignalInfo(ws.StopSignal()),
			SigTrapCauseInfo(ws.TrapCause()))

		if wpid == -1 {
			logger.Error("wpid = -1")
			app.StateCh <- AppFailed
			app.errorCh <- errors.SE("ptrace.App.collect.wpid", "call.error", fmt.Errorf("wpid is -1"))
			// TODO(ivan): Investigate if this code branch leads to sensor becoming stuck.
			//             Should we collectorDoneCh <- 42?
			return
		}

		callSig = 0 // reset
		terminated := false
		eventStop := false
		handleCall := false
		eventCode := 0
		statusCode := 0
		switch {
		case ws.Exited():
			terminated = true
			statusCode = ws.ExitStatus()
		case ws.Signaled():
			terminated = true
			statusCode = int(ws.Signal())

View on GitHub (pinned to 81940d17fa)

Solutions

  1. Check whether the child process died before collection started (correlate with app crash logs)
  2. Handle EINTR by retrying waitpid instead of treating it as fatal
  3. Ensure only the tracer thread waits on the child (avoid competing waitpid calls)
  4. If the sensor gets stuck, force cleanup via collectorDoneCh as the TODO suggests
Defensive patterns

Strategy: try-catch

Try / catch

go func() {
    select {
    case err := <-app.errorCh:
        if se, ok := err.(*errors.Err); ok && se.Code == "ptrace.App.collect.wpid" {
            log.Errorf("collector lost tracee: %v", se)
            // perform cleanup so sensor does not get stuck
            close(collectorDoneCh)
        }
    }
}()

Prevention

When it happens

Trigger: trace() -> collect(): waitpid returns -1 (child already reaped, no children, or interrupted syscall not retried) instead of a valid tracee pid.

Common situations: Child exited and was reaped by another goroutine/thread; EINTR from a signal handler not handled; all tracees already terminated by the time collect waits.

Related errors


AI-assisted analysis of slimtoolkit/slim@81940d17fa (2026-08-31). Data as JSON: /api/errors/d99c887cddd2ccd0. Report an issue: GitHub.