fatedier/frp · error

exec configuration is required when type is 'exec'

Error message

exec configuration is required when type is 'exec'

What it means

Thrown by ValueSource.Validate() in frp's config v1 package when a tokenSource (or other ValueSource) declares type: "exec" but the exec sub-object is missing. ValueSource is used to resolve auth tokens dynamically (pkg/config/v1/client.go TokenSource, server.go TokenSource). The switch dispatches validation to the matching sub-config; a nil Exec block cannot be validated.

Source

Thrown at pkg/config/v1/value_source.go:65

	Name  string `json:"name"`
	Value string `json:"value"`
}

// Validate validates the ValueSource configuration.
func (v *ValueSource) Validate() error {
	if v == nil {
		return errors.New("valueSource cannot be nil")
	}

	switch v.Type {
	case "file":
		if v.File == nil {
			return errors.New("file configuration is required when type is 'file'")
		}
		return v.File.Validate()
	case "exec":
		if v.Exec == nil {
			return errors.New("exec configuration is required when type is 'exec'")
		}
		return v.Exec.Validate()
	default:
		return fmt.Errorf("unsupported value source type: %s (only 'file' and 'exec' are supported)", v.Type)
	}
}

// Resolve resolves the value from the configured source.
func (v *ValueSource) Resolve(ctx context.Context) (string, error) {
	if err := v.Validate(); err != nil {
		return "", err
	}

	switch v.Type {
	case "file":
		return v.File.Resolve(ctx)
	case "exec":
		return v.Exec.Resolve(ctx)

View on GitHub (pinned to 6c8a8d0a97)

Solutions

  1. Add the exec block under tokenSource: [auth.tokenSource.exec] with command = "..." and optional args/env
  2. If you meant to read a file, set type = "file" and provide a [auth.tokenSource.file] block with path
  3. If constructing in Go, populate ValueSource{Type: "exec", Exec: &v1.ExecSource{Command: "..."}}
  4. Run frpc verify -c ./frpc.toml (or frps verify) to validate before starting

Example fix

# before (frpc.toml)
[auth]
tokenSource.type = "exec"

# after
[auth]
tokenSource.type = "exec"
[auth.tokenSource.exec]
command = "/usr/local/bin/get-token"
args = ["--audience", "frps"]
Defensive patterns

Strategy: validation

Validate before calling

// Go: validate before use
if vs := cfg.Auth.TokenSource; vs != nil {
    if vs.Type == "exec" && vs.Exec == nil {
        return fmt.Errorf("tokenSource.type=exec requires an exec block")
    }
    if err := vs.Validate(); err != nil {
        return err
    }
}

Type guard

func hasExecSource(vs *v1.ValueSource) bool {
    return vs != nil && vs.Type == "exec" && vs.Exec != nil
}

Prevention

When it happens

Trigger: Setting tokenSource.type = "exec" in frpc.toml/frps.toml without a [tokenSource.exec] table; building a v1.ValueSource{Type: "exec"} literal in Go with Exec left nil; marshalling YAML/JSON that omits the exec key.

Common situations: Migrating a static auth.token to an exec-based token source and forgetting the command block; typos like type = "Exec" (case-sensitive, would hit the unsupported-type branch instead) or exEc; configs generated by templates that skip the exec section when a variable is empty.

Related errors


AI-assisted analysis of fatedier/frp@6c8a8d0a97 (2026-08-15). Data as JSON: /api/errors/62b9a49a8fc7bcf4. Report an issue: GitHub.