fatedier/frp · error

file configuration is required when type is 'file'

Error message

file configuration is required when type is 'file'

What it means

Validation error from ValueSource.Validate: the value source is declared with type "file" but its File sub-configuration is nil. ValueSource lets config fields (e.g. auth.token, oidc clientSecret) be read from a file or a command instead of a literal value; type "file" requires a matching {path: ...} object describing which file to read. The check runs whenever the config loader validates a ValueSource-typed field.

Source

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

	Args    []string     `json:"args,omitempty"`
	Env     []ExecEnvVar `json:"env,omitempty"`
}

type ExecEnvVar struct {
	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
	}

View on GitHub (pinned to 6c8a8d0a97)

Solutions

  1. Supply the file block: {type = "file", file = {path = "/run/secrets/token"}} so File is non-nil.
  2. Check indentation/nesting: the path key must live inside the file table, not beside type.
  3. If the value should come from a command, use type = "exec" with exec = {command = [...]} instead.
  4. Verify the referenced path exists and is readable by the frp process to avoid the later file-open failure.

Example fix

# before
[auth]
token = {type = "file"}

# after
[auth]
token = {type = "file", file = {path = "/run/secrets/frp-token"}}
Defensive patterns

Strategy: validation

Validate before calling

func valueSourceWellFormed(vs *v1.ValueSource) error {
    if vs == nil {
        return nil // field not using a value source
    }
    switch vs.Type {
    case "file":
        if vs.File == nil {
            return errors.New("type=file requires a file block with path")
        }
    case "exec":
        if vs.Exec == nil {
            return errors.New("type=exec requires an exec block")
        }
    }
    return nil
}

Type guard

func valueSourceComplete(vs v1.ValueSource) bool {
    switch vs.Type {
    case "file":
        return vs.File != nil
    case "exec":
        return vs.Exec != nil
    default:
        return false
    }
}

Try / catch

if err := vs.Validate(); err != nil {
    if strings.Contains(err.Error(), "file configuration is required") {
        // add file = {path = ...} beside type = "file"
    }
    return err
}

Prevention

When it happens

Trigger: A config field using value source syntax with type = "file" but no accompanying file block — e.g. {type = "file"} alone, or the file table nested under the wrong key so File decodes to nil. Also triggered in Go by constructing v1.ValueSource{Type: "file"} without setting File.

Common situations: Migrating secrets from literal strings to file-based sourcing and stopping halfway; YAML/TOML indentation errors putting the path key outside the file table; typo 'path' vs the expected key; JSON configs where "file": null.

Related errors


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