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.

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.

Appendix: 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)