larksuite/cli · error

exec provider: failed to marshal request: %w

Error message

exec provider: failed to marshal request: %w

What it means

marshalExecRequest serializes the exec provider's JSON request (protocol version, provider name, and the secret IDs) before spawning the child process. It wraps any json.Marshal failure with this message. In practice this is nearly unreachable because execRequest contains only plain string/int fields, so a failure indicates a programming or memory error rather than user input.

Source

Thrown at internal/binding/secret_resolve_exec.go:114

		MaxOut:  maxOut,
	}, nil
}

// marshalExecRequest encodes the JSON protocol request sent to the child.
// providerName is supplied by resolveSecretRef after consulting
// secrets.defaults.exec; an empty value falls back to DefaultProviderAlias
// so the function can still be reasoned about in isolation.
func marshalExecRequest(ref *SecretRef, providerName string) ([]byte, error) {
	if providerName == "" {
		providerName = DefaultProviderAlias
	}
	data, err := json.Marshal(execRequest{
		ProtocolVersion: 1,
		Provider:        providerName,
		IDs:             []string{ref.ID},
	})
	if err != nil {
		return nil, fmt.Errorf("exec provider: failed to marshal request: %w", err)
	}
	return data, nil
}

// buildExecEnv assembles the child's environment: only variables listed in
// pc.PassEnv (and non-empty in the parent) plus pc.Env entries. The child
// never inherits the full parent env — always set cmd.Env explicitly.
func buildExecEnv(pc *ProviderConfig, getenv func(string) string) []string {
	env := make([]string, 0, len(pc.PassEnv)+len(pc.Env))
	for _, key := range pc.PassEnv {
		if val := getenv(key); val != "" {
			env = append(env, key+"="+val)
		}
	}
	for key, val := range pc.Env {
		env = append(env, key+"="+val)
	}
	return env

View on GitHub (pinned to 7fd6ef3c07)

Solutions

  1. Check the wrapped cause: if it mentions an unsupported type, inspect recent changes to the execRequest struct in secret_resolve_exec.go and revert or fix the field type
  2. If it appeared after a library upgrade, report/inspect the version change for struct changes
  3. Retry the operation once in case of a transient memory error; if it persists, file a bug with the wrapped error

Example fix

// before (unsupported field added to execRequest)
type execRequest struct {
    ProtocolVersion int
    Provider string
    IDs []string
    Callback func() // json.Marshal fails
}

// after
type execRequest struct {
    ProtocolVersion int
    Provider string
    IDs []string
}
Defensive patterns

Strategy: try-catch

Try / catch

secret, err := resolveSecretRef(ctx, ref)
if err != nil {
    if strings.Contains(err.Error(), "failed to marshal request") {
        return fmt.Errorf("internal exec-provider request serialization failed: %w", err)
    }
    return err
}

Prevention

When it happens

Trigger: prepareExecRun -> marshalExecRequest calls json.Marshal on the execRequest struct and json.Marshal returns a non-nil error (e.g. unsupported type if the struct ever gains an unmarshalable field such as chan/func, or an out-of-memory condition).

Common situations: Essentially only seen after modifying execRequest to include an unsupported field type (channel, func, cyclic pointer) — stock users should never hit this; could surface as an internal error during secret resolution with no user-actionable input.

Understand the failure class

Background: json.Marshal / "failed to marshal" errors in Go: why "unsupported type" happens and how to fix it — this error's family across 22 libraries.

Related errors


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