derailed/k9s · warning
k9s config file %q load failed: %w
Error message
k9s config file %q load failed: %w
What it means
Returned from Config.Load (internal/config/config.go:283) when the main k9s config file fails validation against the K9s JSON schema (data.JSONValidator.Validate with json.K9sSchema). Typically means unknown keys, misspelled keys, or values that changed shape between k9s versions. Errors are joined (errors.Join) — the schema error may arrive together with the unmarshal error from line 288 — and notably Load still merges the parsed config before returning, so the error is advisory: partial config is in effect.
Source
Thrown at internal/config/config.go:283
func (c *Config) Merge(c1 *Config) {
c.K9s.Merge(c1.K9s)
}
// Load loads K9s configuration from file.
func (c *Config) Load(path string, force bool) error {
if _, err := os.Stat(path); errors.Is(err, fs.ErrNotExist) {
if err := c.Save(force); err != nil {
return err
}
}
bb, err := os.ReadFile(path)
if err != nil {
return err
}
var errs error
if err := data.JSONValidator.Validate(json.K9sSchema, bb); err != nil {
errs = errors.Join(errs, fmt.Errorf("k9s config file %q load failed:\n%w", path, err))
}
var cfg Config
if err := yaml.Unmarshal(bb, &cfg); err != nil {
errs = errors.Join(errs, fmt.Errorf("main config.yaml load failed: %w", err))
}
c.Merge(&cfg)
return errs
}
// Save configuration to disk.
func (c *Config) Save(force bool) error {
contextName := c.K9s.ActiveContextName()
// Skip saving if no context is configured
if contextName == "" {
slog.Debug("No context configured, skipping config save")
return nilView on GitHub (pinned to 2d3ccc6ba2)
Solutions
- Read the validator detail in the message — it names the offending key/field and the schema path
- Rename or delete the flagged keys per the current version's config schema
- After a version upgrade, back up and let k9s regenerate a fresh config, then re-apply your customizations
- Keep one k9s version across machines if you sync the config file
Example fix
# before: config.yml after upgrade ui: skin: monokai # removed key in new schema -> validation error # after: check schema, use current key ui: skin: monokai # e.g. renamed to: activeSkin: monokai (per validator message)
Defensive patterns
Strategy: try-catch
Validate before calling
// Pre-validate the config against the shipped schema before k9s loads it:
func configSchemaOK(path string) bool {
bb, err := os.ReadFile(path)
if err != nil {
return false
}
return data.JSONValidator.Validate(json.K9sSchema, bb) == nil
} Try / catch
if err := cfg.Load(path, force); err != nil {
// Load joins schema + unmarshal errors; split them:
var joined interface{ Unwrap() []error }
if errors.As(err, &joined) {
for _, e := range joined.Unwrap() {
if strings.Contains(e.Error(), "load failed") {
// schema/yaml drift: warn, config still partially applied
} else {
// harder failure: inspect
}
}
}
} Prevention
- Back up config.yml before every k9s upgrade (cp config.yml config.yml.$(k9s version))
- After upgrading, launch once, fix keys the validator names, then customize
- Do not sync config.yml between machines running different k9s versions
When it happens
Trigger: Upgrading k9s while the old config.yml contains keys removed from the new schema (or vice versa: a newer config opened by an older k9s); hand-editing with typo'd key names like 'refreshRate' vs 'refreshrate'; structurally valid YAML that violates the schema.
Common situations: k9s major-version upgrades; dotfiles synced across machines running different k9s versions; copy-pasted config snippets from blog posts targeting a different version.
Related errors
- duplicate input name %q
- default value %q for bool input %q must be "true" or "false"
- default value %q for number input %q is not a valid number
- plugin validation failed for %s: %w
- plugin %q validation failed for %s: %w
AI-assisted analysis of derailed/k9s@2d3ccc6ba2 (2026-08-15).
Data as JSON: /api/errors/dc2bd5551e5e2494.
Report an issue: GitHub.