sipeed/picoclaw · error

failed to save config: %w

Error message

failed to save config: %w

What it means

picoclaw model add successfully upserted the model entry in memory and set the default model name, but config.SaveConfig failed to persist it — so nothing was written. The wrapped error carries the cause: marshaling or save-time validation failure, permission denied on the file or directory, a read-only filesystem, or disk full.

Source

Thrown at cmd/picoclaw/internal/model/add.go:195

			m.Enabled = true
			found = true
			break
		}
	}
	if !found {
		cfg.ModelList = append(cfg.ModelList, &config.ModelConfig{
			ModelName: alias,
			Model:     modelID,
			APIBase:   apiBase,
			APIKeys:   secureKeys,
			Enabled:   true,
		})
	}

	cfg.Agents.Defaults.ModelName = alias

	if err := config.SaveConfig(configPath, cfg); err != nil {
		return fmt.Errorf("failed to save config: %w", err)
	}

	fmt.Fprintf(stdout, "✓ Saved model '%s' (%s) and set as default.\n", alias, modelID)
	return nil
}

View on GitHub (pinned to 49183d7e8d)

Solutions

  1. Read the wrapped error: 'permission denied' → chown the config file and its directory to the current user; 'no space left on device' → free space
  2. After earlier sudo runs, fix ownership: sudo chown -R $(id -u):$(id -g) <config-dir>
  3. Re-run the command once fixed — since the save failed, there is no partial state to clean up
  4. For validation failures, fix the field named in the error and retry

Example fix

# before
$ picoclaw model add -b ... -k ... -m gpt-4o-mini
failed to save config: ... permission denied

# after
$ sudo chown -R $(id -u):$(id -g) ~/.config/picoclaw
$ picoclaw model add -b ... -k ... -m gpt-4o-mini
Defensive patterns

Strategy: try-catch

Validate before calling

configPath := internal.GetConfigPath()
f, err := os.OpenFile(configPath, os.O_WRONLY|os.O_APPEND, 0)
if err != nil {
  return fmt.Errorf("config %s not writable: %w", configPath, err)
}
f.Close()

Type guard

func isConfigSaveError(err error) bool {
  return err != nil && strings.Contains(err.Error(), "failed to save config")
}

func isPermissionErr(err error) bool {
  return errors.Is(err, os.ErrPermission) // through the %w chain
}

Try / catch

if err := config.SaveConfig(configPath, cfg); err != nil {
  if errors.Is(err, os.ErrPermission) {
    // guide: chown the config dir, or rerun with corrected ownership; state was not persisted
  }
  if errors.Is(err, fs.ErrNoSpace) {
    // alert on disk space; safe to retry after cleanup
  }
  return fmt.Errorf("failed to save config: %w", err)
}

Prevention

When it happens

Trigger: Config file or its directory owned by root after earlier sudo use while now running as a normal user; read-only mount (container, WSL); disk-full; a config state that fails picoclaw's save-time validation.

Common situations: Mixed sudo/non-sudo invocations leaving root-owned config files; containers with read-only home; CI runners out of disk; configs with fields that fail validation on write.

Related errors


AI-assisted analysis of sipeed/picoclaw@49183d7e8d (2026-08-15). Data as JSON: /api/errors/283076469fa54d4b. Report an issue: GitHub.