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
- Re-run `lark-cli config init` in an interactive terminal and type values, finishing with enter rather than Ctrl-D.
- Abort with Ctrl-C if you want to cancel, and use `lark-cli config init --new` for unattended creation.
- 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
- Cancel prompts with Ctrl-C, not Ctrl-D.
- Re-run the wizard rather than answering prompts from files/pipes.
- Use `config init --new` for any unattended environment.
- Verify terminal multiplexer sessions are attached before starting.
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
- failed to read input: %w
- failed to read stdin: %w
- please select at least one domain
- stdin is empty (did you forget to pipe input?)
- invalid chart size: {size!r}
AI-assisted analysis of larksuite/cli@7fd6ef3c07 (2026-09-04).
Data as JSON: /api/errors/eb518ebac8400b1b.
Report an issue: GitHub.