larksuite/cli · error

%s must not be empty

Error message

%s must not be empty

What it means

safePath (shared by SafeOutputPath and SafeInputPath) rejects a value that is empty or whitespace-only after the control-character check, prefixing the message with the flag name. An empty path can never satisfy the allowlist policy, so it fails early with a clear message.

Source

Thrown at internal/vfs/localfileio/path.go:153

	resolved, err := resolveNearestAncestor(path)
	if err != nil {
		return "", fmt.Errorf("cannot resolve symlinks: %w", err)
	}
	return resolved, nil
}

// safePath is the shared implementation for SafeOutputPath and SafeInputPath.
// A path is accepted when its real location falls inside the built-in
// allowlist (cwd, /tmp, ~/files) and outside the built-in denylist; deny wins
// over allow, cwd included. Both lists are compiled in (policy.go), which
// also documents the two bounded environment inputs that remain.
func safePath(raw, flagName string) (string, error) {
	isOutputFlag := flagName == "--output"
	if err := charcheck.RejectControlChars(raw, flagName); err != nil {
		return "", err
	}
	if strings.TrimSpace(raw) == "" {
		return "", fmt.Errorf("%s must not be empty", flagName)
	}
	if err := validatePathPlatform(raw); err != nil {
		return "", fmt.Errorf("%s: %w", flagName, err)
	}
	if err := rejectForeignAbsolute(raw, flagName); err != nil {
		return "", err
	}

	cwd, err := vfs.Getwd()
	if err != nil {
		return "", fmt.Errorf("cannot determine working directory: %w", err)
	}
	// Every reading of the argument must pass, not just the one this function
	// returns: callers that keep the original string (SafeLocalFlagPath does)
	// open the location the OS computes, and for a "~/..." argument that is a
	// literal "~" entry in the working directory rather than the home
	// directory. A path is only safe when both readings are.
	interps, err := interpretations(raw, cwd)

View on GitHub (pinned to 7fd6ef3c07)

Solutions

  1. Provide a concrete value for the flag before invoking the command
  2. Guard in shell: `: "${OUTPUT:?OUTPUT not set}"` before running
  3. Fix the templating/config so the placeholder is actually filled

Example fix

// before
cmd.Flags().String("output", cfg.Output, "") // cfg.Output == ""
// error: --output must not be empty
// after
if cfg.Output == "" {
    cfg.Output = "./out.bin"
}
cmd.Flags().String("output", cfg.Output, "")
Defensive patterns

Strategy: validation

Validate before calling

if strings.TrimSpace(out) == "" {
    return errors.New("--output is required")
}

Type guard

func hasOutputPath(v string) bool { return strings.TrimSpace(v) != "" }

Try / catch

if _, err := localfileio.SafeOutputPath(flagValue); err != nil {
    return fmt.Errorf("--output: %w", err)
}

Prevention

When it happens

Trigger: Calling SafeOutputPath("") or SafeInputPath(" ") — an --output/--file flag bound to an unset variable, an empty config field, or a templating placeholder like {{output}} left unsubstituted.

Common situations: Script variable $OUT never set; YAML/JSON config with an empty string value; templated command where the substitution failed; shell ${VAR} expanding to empty because an earlier step produced no output.

Related errors


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