larksuite/cli · error

stdin is not available

Error message

stdin is not available

What it means

ResolveInput in internal/cmdutil/resolve.go maps the special flag value '-' to 'read the body from stdin'. If the caller passed a nil stdin io.Reader (a context where stdin was not wired up), there is nothing to read, so it fails fast with 'stdin is not available' instead of panicking on a nil reader.

Source

Thrown at internal/cmdutil/resolve.go:35

//   - "@<path>" → read all bytes from the file at <path> via fileIO
//   - "@@..."   → strip leading @ (escape for a literal @-prefixed value)
//   - "'...'"   → strip surrounding single quotes (Windows cmd.exe compatibility)
//   - other     → return as-is
//
// 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

View on GitHub (pinned to 7fd6ef3c07)

Solutions

  1. Pipe the input in, e.g. `echo '{...}' | lark-cli ...` or redirect: `cmd - < body.json`.
  2. Use the '@<path>' form to read the body from a file instead of stdin.
  3. If invoking programmatically, pass a non-nil io.Reader (strings.Reader or os.Stdin) to ResolveInput.

Example fix

// before (no stdin attached)
lark-cli service call ... --body -
// after
echo '{"k":"v"}' | lark-cli service call ... --body -
# or
lark-cli service call ... --body @body.json
Defensive patterns

Strategy: validation

Validate before calling

if bodyFlag == "-" && stdinUnavailable {
	bodyFlag = "@body.json" // fall back to file input
}

Type guard

func stdinAvailable(r io.Reader) bool { return r != nil }

Try / catch

val, err := cmdutil.ResolveInput(raw, stdin, fileIO)
if err != nil {
	if strings.Contains(err.Error(), "stdin is not available") {
		return fmt.Errorf("pass a file via @path or pipe input to stdin: %w", err)
	}
	return err
}

Prevention

When it happens

Trigger: Passing '-' as a raw flag value (e.g. a body/payload flag) through ParseOptionalBody/ParseJSONMap where ResolveInput received stdin == nil — typically embedded CLI use without os.Stdin, or an environment with stdin detached.

Common situations: Running the CLI from CI with stdin closed while using '-' for the body flag; calling the library function directly with nil stdin; schedulers that detach standard input.

Related errors


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