larksuite/cli · error

failed to read stdin: %w

Error message

failed to read stdin: %w

What it means

ResolveInput reads piped stdin when the input value is the literal "-". This error wraps an underlying I/O failure returned by io.ReadAll on the stdin reader, preserving the cause via %w. It signals the pipe/reader broke mid-read rather than an empty or missing input.

Source

Thrown at internal/cmdutil/resolve.go:39

//
// fileIO is required for "@<path>" inputs and goes through path validation
// (SafeInputPath); pass nil only when callers know "@" inputs are not possible.
//
// Allows callers to bypass shell quoting issues (especially Windows PowerShell 5)
// by reading JSON from a file (@path) or piping via stdin (-).
func ResolveInput(raw string, stdin io.Reader, fileIO fileio.FileIO) (string, error) {
	if raw == "" {
		return "", nil
	}

	// stdin
	if raw == "-" {
		if stdin == nil {
			return "", fmt.Errorf("stdin is not available")
		}
		data, err := io.ReadAll(stdin)
		if err != nil {
			return "", fmt.Errorf("failed to read stdin: %w", err)
		}
		s := strings.TrimSpace(string(data))
		if s == "" {
			return "", fmt.Errorf("stdin is empty (did you forget to pipe input?)")
		}
		return s, nil
	}

	// escape: @@... → literal @... (no file read)
	if strings.HasPrefix(raw, "@@") {
		return raw[1:], nil
	}

	// file: @path
	if strings.HasPrefix(raw, "@") {
		path := strings.TrimSpace(raw[1:])
		if path == "" {
			return "", fmt.Errorf("file path cannot be empty after @")

View on GitHub (pinned to 7fd6ef3c07)

Solutions

  1. Check the wrapped cause (errors.Unwrap / %v) to identify the underlying I/O error
  2. Fix the pipeline so the producer stays alive until the CLI finishes reading stdin
  3. Verify stdin is a readable pipe, not a closed or write-only descriptor
  4. If no input is intended, pass a literal value or @file instead of "-"

Example fix

// before
echo x | broken-producer | lark-cli cmd --body -
// after
producer-ok | lark-cli cmd --body -
Defensive patterns

Strategy: try-catch

Try / catch

val, err := cmdutil.ResolveInput("-", fileIO, os.Stdin)
if err != nil {
    var wrapped interface{ Unwrap() error }
    if errors.As(err, &wrapped) { log.Printf("stdin read cause: %v", errors.Unwrap(err)) }
    return err
}

Prevention

When it happens

Trigger: Calling ParseOptionalBody or ParseJSONMap with a flag value of "-" while the process stdin reader returns a read error (e.g. closed pipe, I/O error on the underlying fd, reader supplied via stdin param fails).

Common situations: Upstream process in a shell pipeline exited early closing the pipe; running under a environment where stdin is a failing pseudo-device; custom FileIO/test harness injecting a failing reader.

Related errors


AI-assisted analysis of larksuite/cli@7fd6ef3c07 (2026-09-04). Data as JSON: /api/errors/dfdaf47938de63a0. Report an issue: GitHub.