larksuite/cli · error

failed to read input: %w

Error message

failed to read input: %w

What it means

`lark-cli config init` legacy interactive mode reads each answer with bufio.Reader.ReadString('\n'). If reading fails with a non-EOF error (I/O failure on stdin), the error is wrapped as "failed to read input". An EOF with an empty line produces the distinct "input terminated unexpectedly (EOF)" error instead.

Source

Thrown at cmd/config/init.go:502

	}

	// Non-terminal: cannot run interactive mode, guide user to --new
	if !f.IOStreams.IsTerminal {
		return errs.NewValidationError(errs.SubtypeInvalidArgument, "config init requires a terminal for interactive mode. Run with --new to create a new app:\n  lark-cli config init --new\nThis command blocks until setup is complete and outputs a verification URL. Run it in the background, then retrieve the URL from its output.")
	}

	// Mode 5: Legacy interactive (readline fallback)
	firstApp := (*core.AppConfig)(nil)
	if existing != nil {
		firstApp = existing.CurrentAppConfig("")
	}

	reader := bufio.NewReader(f.IOStreams.In)
	readLine := func(prompt string) (string, error) {
		fmt.Fprintf(f.IOStreams.ErrOut, "%s: ", prompt)
		line, err := reader.ReadString('\n')
		if err != nil && err != io.EOF {
			return "", fmt.Errorf("failed to read input: %w", err)
		}
		if err == io.EOF && strings.TrimSpace(line) == "" {
			return "", fmt.Errorf("input terminated unexpectedly (EOF)")
		}
		return strings.TrimSpace(line), nil
	}

	prompt := "App ID"
	if firstApp != nil && firstApp.AppId != "" {
		prompt += fmt.Sprintf(" [%s]", firstApp.AppId)
	}
	appIdInput, err := readLine(prompt)
	if err != nil {
		return errs.NewValidationError(errs.SubtypeInvalidArgument, "%s", err).WithCause(err)
	}

	prompt = "App Secret"
	if firstApp != nil && !firstApp.AppSecret.IsZero() {

View on GitHub (pinned to 7fd6ef3c07)

Solutions

  1. Run the command in a real interactive terminal so stdin is open and readable.
  2. If scripting, use the non-interactive path: `lark-cli config init --new`, or provide config via flags/env instead of piping answers.
  3. Check for and fix wrappers/CI steps that close or redirect stdin (e.g. `< /dev/null`), or use `script -c` / a pseudo-TTY if interaction is unavoidable.

Example fix

// before: piping answers into an interactive command fails on stdin
$ echo "cli_x\nsecret" | lark-cli config init
// after: use the non-interactive creation path
$ lark-cli config init --new   # blocks until setup completes, prints verification URL
Defensive patterns

Strategy: fallback

Validate before calling

// Guard before running interactive init
if !term.IsTerminal(int(os.Stdin.Fd())) {
	return errors.New("config init requires a TTY; run with --new for non-interactive setup")
}

Try / catch

if err := runConfigInit(); err != nil {
	if strings.Contains(err.Error(), "failed to read input") {
		// fall back to non-interactive creation
		return runConfigInitNew()
	}
	return err
}

Prevention

When it happens

Trigger: Running config init when the stdin read fails at the OS level: stdin closed by the shell, a broken pipe from a scripted invocation, device errors, or the input stream being reset mid-prompt.

Common situations: Invoking the interactive command inside CI or a non-interactive shell where stdin is /dev/null or a closed fd; a parent process killing the pipe; running under a wrapper that does not allocate a TTY.

Related errors


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