henrygd/beszel · error

failed to parse config.yml: %v

Error message

failed to parse config.yml: %v

What it means

SyncSystems reads config.yml and unmarshals it with yaml.Unmarshal into the internal config struct. This error wraps any YAML parsing or structural decoding failure, meaning the file could not be interpreted as valid YAML matching the expected schema. SyncSystems aborts before touching any PocketBase records.

Source

Thrown at internal/hub/config/config.go:43

	Host  string   `yaml:"host"`
	Port  uint16   `yaml:"port,omitempty"`
	Token string   `yaml:"token,omitempty"`
	Users []string `yaml:"users"`
}

// Syncs systems with the config.yml file
func SyncSystems(e *core.ServeEvent) error {
	h := e.App
	configPath := filepath.Join(h.DataDir(), "config.yml")
	configData, err := os.ReadFile(configPath)
	if err != nil {
		return nil
	}

	var config config
	err = yaml.Unmarshal(configData, &config)
	if err != nil {
		return fmt.Errorf("failed to parse config.yml: %v", err)
	}

	if len(config.Systems) == 0 {
		log.Println("No systems defined in config.yml.")
		return nil
	}

	var firstUser *core.Record

	// Create a map of email to user ID
	userEmailToID := make(map[string]string)
	users, err := h.FindAllRecords("users", dbx.NewExp("id != ''"))
	if err != nil {
		return err
	}
	if len(users) > 0 {
		firstUser = users[0]
		for _, user := range users {

View on GitHub (pinned to b38fb7dafa)

Solutions

  1. Read the wrapped %v message — it names the exact line and YAML problem (e.g. 'line 4: cannot unmarshal !!str into int').
  2. Validate the file with a linter: `yamllint config.yml` or paste into a YAML validator; replace tabs with spaces.
  3. Fix field types to match the schema (systems list with name/host/port/users fields, port numeric).
  4. Restore from a known-good config or version-controlled copy, then re-run SyncSystems.

Example fix

// before: invalid config.yml
tab-indented: true
	 systems:
  - name: web

// after: consistent two-space indentation, correct types
systems:
  - name: web
    host: 10.0.0.5
    port: 22
Defensive patterns

Strategy: validation

Validate before calling

data, err := os.ReadFile("config.yml")
if err != nil { return err }
var probe map[string]any
if err := yaml.Unmarshal(data, &probe); err != nil {
    return fmt.Errorf("config.yml is not valid YAML: %w", err)
}
if _, ok := probe["systems"]; !ok { return fmt.Errorf("config.yml missing 'systems' key") }

Type guard

func isYAMLSyntaxError(err error) bool {
    var te *yaml.TypeError
    if errors.As(err, &te) { return false }
    return err != nil // unmarshal errors that aren't TypeError are syntax errors
}

Try / catch

if err := SyncSystems(); err != nil {
    if strings.Contains(err.Error(), "failed to parse config.yml") {
        return fmt.Errorf("fix config.yml before syncing: %w", err) // do not retry until edited
    }
    return err
}

Prevention

When it happens

Trigger: Calling SyncSystems when configData contains invalid YAML — bad indentation, tabs instead of spaces, unquoted special characters, or fields whose types don't match the config struct (e.g. port as a string instead of int).

Common situations: Hand-edited config.yml with a tab character or wrong indentation; YAML anchors/aliases or multiline strings misused; a value like `port: "8080"` where an int is expected; encoding issues (BOM, non-UTF8) introduced by editors.

Understand the failure class

Related errors


AI-assisted analysis of henrygd/beszel@b38fb7dafa (2026-08-31). Data as JSON: /api/errors/ecea9098372e5b5f. Report an issue: GitHub.