larksuite/cli · warning

input terminated unexpectedly (EOF)

Error message

input terminated unexpectedly (EOF)

What it means

In `lark-cli config init` legacy interactive mode, when ReadString returns io.EOF and the accumulated line is empty/whitespace, the command reports "input terminated unexpectedly (EOF)" because stdin ended before an answer was given. The caller wraps it into a validation error.

Source

Thrown at cmd/config/init.go:505

	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() {
		prompt += " [****]"
	}
	appSecretInput, err := readLine(prompt)

View on GitHub (pinned to 7fd6ef3c07)

Solutions

  1. Re-run `lark-cli config init` in an interactive terminal and type values, finishing with enter rather than Ctrl-D.
  2. Abort with Ctrl-C if you want to cancel, and use `lark-cli config init --new` for unattended creation.
  3. If scripting, supply config non-interactively (flags/config file/env) instead of relying on the interactive prompts.

Example fix

// before: EOF at prompt
App ID: (Ctrl-D) -> input terminated unexpectedly (EOF)
// after
App ID: cli_a1b2c3 (enter)  # or abort with Ctrl-C / use config init --new
Defensive patterns

Strategy: fallback

Validate before calling

// Detect non-character-device stdin before prompting
stat, _ := os.Stdin.Stat()
if stat != nil && (stat.Mode()&os.ModeCharDevice) == 0 {
	return errors.New("stdin is not a terminal; refusing interactive prompt")
}

Try / catch

err := runConfigInit()
if err != nil && strings.Contains(err.Error(), "input terminated unexpectedly") {
	log.Println("interactive setup aborted at EOF; falling back to config init --new")
	return runConfigInitNew()
}

Prevention

When it happens

Trigger: Pressing Ctrl-D (EOF) at the App ID / App Secret / Brand prompt with nothing typed; running the interactive command with stdin from an empty file, /dev/null, or a closed pipe in a TTY-claiming environment.

Common situations: Aborting the wizard with Ctrl-D instead of Ctrl-C; CI jobs that pass the terminal check but feed empty stdin; terminal multiplexer sessions detaching mid-prompt.

Related errors


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