larksuite/cli · error

singleValue file provider expects ref id %q, got %q

Error message

singleValue file provider expects ref id %q, got %q

What it means

In singleValue mode the entire file content is the secret, so OpenClaw semantics require the SecretRef id to equal the sentinel SingleValueFileRefID. A different id means the config is inconsistent: the provider would otherwise silently ignore which id the caller asked for.

Source

Thrown at internal/binding/secret_resolve_file.go:77

	if err != nil {
		return "", fmt.Errorf("failed to read secret file %s: %w", securePath, err)
	}

	if len(data) > maxBytes {
		return "", fmt.Errorf("file provider exceeded maxBytes (%d)", maxBytes)
	}

	content := string(data)
	mode := pc.Mode
	if mode == "" {
		mode = "json" // default mode per OpenClaw
	}

	switch mode {
	case "singleValue":
		// OpenClaw requires ref.id == SINGLE_VALUE_FILE_REF_ID for singleValue mode
		if ref.ID != SingleValueFileRefID {
			return "", fmt.Errorf("singleValue file provider expects ref id %q, got %q",
				SingleValueFileRefID, ref.ID)
		}
		// Entire file content is the secret; trim trailing newline
		return strings.TrimRight(content, "\r\n"), nil

	case "json":
		// Parse as JSON, then navigate via JSON Pointer (ref.ID)
		var parsed interface{}
		if err := json.Unmarshal(data, &parsed); err != nil {
			return "", fmt.Errorf("file provider JSON parse error: %w", err)
		}

		value, err := ReadJSONPointer(parsed, ref.ID)
		if err != nil {
			return "", fmt.Errorf("file provider JSON Pointer %q: %w", ref.ID, err)
		}

		// Value must be a string

View on GitHub (pinned to 7fd6ef3c07)

Solutions

  1. Change the SecretRef id to SingleValueFileRefID when using singleValue mode.
  2. Or, if you need per-key lookup, switch ProviderConfig.Mode to "json" and keep your pointer id.
  3. Audit provider mode and ref id pairs in the binding config so they stay consistent.

Example fix

// before
{"source":"file","id":"/api_key"}  // mode: singleValue
// after
{"source":"file","id":"SINGLE_VALUE_FILE_REF_ID"}  // use the exported sentinel constant's value
// or set provider mode to "json" and keep the pointer id
Defensive patterns

Strategy: validation

Validate before calling

if pc.Mode == "singleValue" && ref.ID != SingleValueFileRefID {
    return fmt.Errorf("config error: singleValue mode requires ref id %q", SingleValueFileRefID)
}

Try / catch

secret, err := resolveSecretRef(ctx, ref)
if err != nil {
    if strings.Contains(err.Error(), "expects ref id") {
        // fix the ref id or switch the provider mode to json
    }
    return err
}

Prevention

When it happens

Trigger: Calling resolveSecretRef with a {source:"file"} SecretRef whose ProviderConfig.Mode is "singleValue" but whose ref.ID is not SingleValueFileRefID (e.g. a leftover JSON-pointer-style id like "/api_key" from a json-mode config).

Common situations: Switching a provider from json to singleValue mode without updating the ref id; copying a ref from a json-mode provider; hand-writing the ref with an intuitive custom id.

Related errors


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