hyperledger/fabric · error

Value of File: was nil

Error message

Value of File: was nil

What it means

stringFromFileDecodeHook is a viper decode hook that reads a config value from a file when the value is given as a map like { file: /path/to/key.pem }. If the map contains a "File"/"file" key whose value is nil, the hook cannot read any file and returns this error instead of silently producing an empty string.

Source

Thrown at common/viperutil/config_util.go:296

	switch v.Kind() {
	case reflect.String:
		return data, nil
	case reflect.Map:
		d := data.(map[string]any)
		fileName, ok := d["File"]
		if !ok {
			fileName, ok = d["file"]
		}
		switch {
		case ok && fileName != nil:
			bytes, err := os.ReadFile(fileName.(string))
			if err != nil {
				return data, err
			}
			return string(bytes), nil
		case ok:
			// fileName was nil
			return nil, fmt.Errorf("Value of File: was nil")
		}
	}
	return data, nil
}

func pemBlocksFromFileDecodeHook(f reflect.Kind, t reflect.Kind, data any) (any, error) {
	// "to" type should be string
	if t != reflect.Slice {
		return data, nil
	}
	// "from" type should be map
	if f != reflect.Map {
		return data, nil
	}
	v := reflect.ValueOf(data)
	switch v.Kind() {
	case reflect.String:
		return data, nil

View on GitHub (pinned to 2736b63f8f)

Solutions

  1. Set an actual file path under the File key, e.g. File: /path/to/cert.pem.
  2. If the value should be inline, replace the map with the literal string instead of an empty File map.
  3. Check template/Helm rendering so the path variable isn't empty at deploy time.
  4. Verify the file key spelling and that no overriding env var sets it to nil/empty.

Example fix

// before (config.yaml)
externalListeners:
  - Certificate: File:
# after
externalListeners:
  - Certificate:
      File: /etc/hyperledger/fabric/tls/server.crt
Defensive patterns

Strategy: validation

Validate before calling

// Reject nil-valued File maps before viper unmarshal
func checkFileIndirection(cfg map[string]any) error {
	var walk func(m map[string]any) error
	walk = func(m map[string]any) error {
		for k, v := range m {
			if (k == "File" || k == "file") && v == nil {
				return fmt.Errorf("File key present but nil at %s", k)
			}
			if sub, ok := v.(map[string]any); ok {
				if err := walk(sub); err != nil { return err }
			}
		}
		return nil
	}
	return walk(cfg)
}

Type guard

func hasFileValue(m map[string]any) (string, bool) {
	v, ok := m["File"]
	if !ok { v, ok = m["file"] }
	if !ok || v == nil { return "", false }
	s, ok := v.(string)
	return s, ok && s != ""
}

Try / catch

err := viper.Unmarshal(cfg, viperutil.DecodeHookFunc)
if err != nil {
	if strings.Contains(err.Error(), "Value of File: was nil") {
		return fmt.Errorf("a File: config entry has no path set; check YAML rendering: %w", err)
	}
	return err
}

Prevention

When it happens

Trigger: A viper config (YAML/TOML or programmatically built map) supplies a value such as "File:" or {"file": nil} for a string field that supports the file-indirection syntax — the key exists but its value is nil.

Common situations: YAML entries like "tls.cert: File:" left with no value after template rendering, env-var overrides that blank out the file path, or Helm/templating substituting an empty variable into the file key.

Understand the failure class

Background: "missing required config value" errors: why libraries refuse to start when a configuration key is empty, unset, or blank — this error's family across 48 libraries.

Related errors


AI-assisted analysis of hyperledger/fabric@2736b63f8f (2026-09-04). Data as JSON: /api/errors/e000f2d573dd14bf. Report an issue: GitHub.