sipeed/picoclaw · error

failed to load config: %w

Error message

failed to load config: %w

What it means

internal.LoadConfig (cmd/picoclaw/internal/helpers.go:27) failed while preparing the WeCom login flow. LoadConfig reads config.json from $PICOCLAW_CONFIG_PATH or ~/.picoclaw/config.json; a missing file returns defaults without error, so this error means the file exists but is unreadable, contains malformed JSON (reported via wrapJSONError diagnostics), or a config schema migration (V0→V1→V2→V3) failed.

Source

Thrown at cmd/picoclaw/internal/auth/wecom.go:116

	return authWeComCmdWithScanner(context.Background(), os.Stdout, timeout, scanWeComQRCodeInteractive)
}

func authWeComCmdWithScanner(
	ctx context.Context,
	writer io.Writer,
	timeout time.Duration,
	scanner wecomQRScanner,
) error {
	if scanner == nil {
		return fmt.Errorf("wecom QR scanner is nil")
	}
	if writer == nil {
		writer = os.Stdout
	}

	cfg, err := internal.LoadConfig()
	if err != nil {
		return fmt.Errorf("failed to load config: %w", err)
	}

	opts := defaultWeComQRFlowOptions(timeout)
	opts.Writer = writer

	botInfo, err := scanner(ctx, opts)
	if err != nil {
		return err
	}

	applyWeComAuthResult(cfg, botInfo)

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

	fmt.Fprintln(writer)
	fmt.Fprintln(writer, "WeCom connected.")

View on GitHub (pinned to 49183d7e8d)

Solutions

  1. Run the same load outside the flow (e.g. a status command) to see the detailed diagnostic line logged by LoadConfig, which names the exact JSON offset
  2. Validate config.json syntax with a JSON linter (e.g. jq . ~/.picoclaw/config.json)
  3. Fix permissions: chown the file to your user and ensure it is readable/writable (0600)
  4. If the file is a legacy version that fails migration, back it up and let picoclaw regenerate a default config, then re-add settings
  5. Check PICOCLAW_CONFIG_PATH / PICOCLAW_HOME env vars point at the intended file

Example fix

// before
cfg, err := internal.LoadConfig()
if err != nil {
	return fmt.Errorf("failed to load config: %w", err)
}

// after: tell the user exactly which file failed
cfg, err := internal.LoadConfig()
if err != nil {
	return fmt.Errorf("failed to load config %s: %w\nvalidate with: jq . %s", internal.GetConfigPath(), err, internal.GetConfigPath())
}
Defensive patterns

Strategy: validation

Validate before calling

// Fail fast with a clear message before starting an interactive flow
path := internal.GetConfigPath()
if data, err := os.ReadFile(path); err == nil {
	if !json.Valid(data) {
		return fmt.Errorf("%s is not valid JSON — fix it before continuing", path)
	}
}

Type guard

func isConfigSyntaxError(err error) bool {
	var syn *json.SyntaxError
	return errors.As(err, &syn)
}

Try / catch

cfg, err := internal.LoadConfig()
if err != nil {
	if isConfigSyntaxError(err) {
		return fmt.Errorf("config file has a JSON syntax error at offset — run: jq . %s", internal.GetConfigPath())
	}
	return fmt.Errorf("failed to load config: %w", err)
}

Prevention

When it happens

Trigger: Hand-edited config.json with invalid JSON; config file with wrong permissions or an unreadable path; a legacy version-0 config whose migration fails; PICOCLAW_CONFIG_PATH pointing at a directory or corrupt file.

Common situations: User manually edits ~/.picoclaw/config.json and leaves a trailing comma; an older picoclaw version wrote a schema the current migration cannot handle; file owned by root after running with sudo.

Related errors


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