larksuite/cli · error

file provider path is empty

Error message

file provider path is empty

What it means

The file secret provider requires a filesystem path in its ProviderConfig, and none was supplied (pc.Path == ""). The resolver fails fast before attempting any file access or security audit, because there is no file to read for the secret.

Source

Thrown at internal/binding/secret_resolve_file.go:23

import (
	"encoding/json"
	"fmt"
	"strings"

	"github.com/larksuite/cli/internal/vfs"
)

// SingleValueFileRefID is the required ref.ID for singleValue file mode
// (aligned with OpenClaw ref-contract.ts SINGLE_VALUE_FILE_REF_ID).
const SingleValueFileRefID = "$SINGLE_VALUE"

// resolveFileRef handles {source:"file"} SecretRef resolution.
// Reads the file via assertSecurePath audit, then extracts the secret value
// based on the provider's mode (singleValue or json with JSON Pointer).
func resolveFileRef(ref *SecretRef, pc *ProviderConfig) (string, error) {
	if pc.Path == "" {
		return "", fmt.Errorf("file provider path is empty")
	}

	// OpenClaw preserves user-authored `~/...` paths verbatim on disk for
	// portability and resolves them at read time. lark-cli reads the file
	// raw, so we mirror that resolution here before the audit — otherwise
	// an unambiguous home-relative path would be rejected by
	// requireAbsolutePath, which is meant to guard against cwd-relative
	// paths (a different concern). expandTildePath honours OPENCLAW_HOME so
	// a tilde inside an OPENCLAW_HOME-overridden config resolves to the
	// same absolute path OpenClaw itself would have used.
	targetPath := expandTildePath(pc.Path)

	// Security audit on file path
	securePath, err := AssertSecurePath(AuditParams{
		TargetPath:            targetPath,
		Label:                 "secrets.providers file path",
		TrustedDirs:           pc.TrustedDirs,
		AllowInsecurePath:     pc.AllowInsecurePath,

View on GitHub (pinned to 7fd6ef3c07)

Solutions

  1. Set ProviderConfig.Path to the secret file location in the provider config.
  2. Check the config file/env source that populates Path — a missing or empty variable likely interpolated to "".
  3. Add startup validation of the binding config so an empty path is rejected before secret resolution.

Example fix

// before
providers:
  mysecret:
    source: file
    # path missing
// after
providers:
  mysecret:
    source: file
    path: ~/.config/myapp/secrets.json
Defensive patterns

Strategy: validation

Validate before calling

if pc.Source == "file" && pc.Path == "" {
    return fmt.Errorf("file provider %q requires a non-empty path", name)
}

Type guard

func hasFilePath(pc *ProviderConfig) bool { return pc != nil && pc.Path != "" }

Try / catch

secret, err := resolveSecretRef(ctx, ref)
if err != nil {
    if strings.Contains(err.Error(), "path is empty") {
        return fmt.Errorf("check provider config: file source needs 'path'")
    }
    return err
}

Prevention

When it happens

Trigger: Calling resolveSecretRef with a {source:"file"} SecretRef whose ProviderConfig has Path set to the empty string, or the provider config was constructed/decoded without the path field.

Common situations: A YAML/JSON binding config omits the `path` key for the file provider; an env var feeding the path was unset so the config interpolated to ""; a refactor renamed the field so the value no longer populates Path.

Related errors


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