larksuite/cli · error

stdin is empty (did you forget to pipe input?)

Error message

stdin is empty (did you forget to pipe input?)

What it means

ResolveInput trims whitespace from stdin data and rejects it when nothing remains. The library throws this so commands never silently submit an empty body caused by an unplumbed or accidentally empty pipe. The message is a hint that the user likely forgot to pipe input.

Source

Thrown at internal/cmdutil/resolve.go:43

// 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 @")
		}
		data, err := ReadInputFile(fileIO, path)
		if err != nil {
			return "", err

View on GitHub (pinned to 7fd6ef3c07)

Solutions

  1. Pipe the payload into the command, e.g. echo '{...}' | lark-cli cmd --body -
  2. Verify the upstream producer actually emits non-empty output
  3. Use @path-to-file instead of "-" if the payload already exists on disk
  4. Quote/escape correctly so "-" is passed as the flag value, not consumed by the shell

Example fix

// before
lark-cli im message create --body -
// after
echo '{"receive_id":"ou_x","content":"{}"}' | lark-cli im message create --body -
Defensive patterns

Strategy: validation

Validate before calling

// before running with "-":
if [ -t 0 ]; then echo "stdin is a TTY: nothing piped"; exit 1; fi
# or in Go:
fi, _ := os.Stdin.Stat(); if fi.Mode()&os.ModeCharDevice != 0 { /* no piped input */ }

Try / catch

if err != nil && strings.Contains(err.Error(), "stdin is empty") {
    fmt.Fprintln(os.Stderr, "hint: pipe the JSON body, e.g. echo '{...}' | cmd --body -")
}

Prevention

When it happens

Trigger: Passing "-" as the input to ParseOptionalBody/ParseJSONMap while running the command without piping anything (or piping only whitespace/newlines) into stdin.

Common situations: Forgetting the echo/cat pipe in a shell one-liner; piping an empty file; copying a documented pipeline but omitting the producer; CI step where the upstream step produced no output.

Related errors


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