sipeed/picoclaw · error

failed to create api client: %w

Error message

failed to create api client: %w

What it means

The Weixin QR login flow could not even construct its API client, wrapping the error from NewApiClient. Given NewApiClient only fails on an unparseable proxy URL (error 666), this error almost always means opts.Proxy is malformed — the default BaseURL is filled in beforehand so it is never empty at this point. Nothing has touched the network yet when this is returned.

Source

Thrown at pkg/channels/weixin/auth.go:41

// It prints a QR code to the terminal for the user to scan.
// Returns the BotToken, UserID, AccountID, and BaseUrl on success.
func PerformLoginInteractive(
	ctx context.Context,
	opts AuthFlowOpts,
) (botToken, userID, accountID, baseUrl string, err error) {
	if opts.BaseURL == "" {
		opts.BaseURL = "https://ilinkai.weixin.qq.com/"
	}
	if opts.BotType == "" {
		opts.BotType = "3" // Default iLink Bot Type
	}
	if opts.Timeout == 0 {
		opts.Timeout = 5 * time.Minute
	}

	api, err := NewApiClient(opts.BaseURL, "", opts.Proxy)
	if err != nil {
		return "", "", "", "", fmt.Errorf("failed to create api client: %w", err)
	}
	pollAPI := api

	logger.InfoC("weixin", "Requesting Weixin QR code...")
	qrResp, err := api.GetQRCode(ctx, opts.BotType)
	if err != nil {
		return "", "", "", "", fmt.Errorf("failed to get qrcode: %w", err)
	}

	fmt.Println("\n=======================================================")
	fmt.Println("Please scan the following QR code with WeChat to login:")
	fmt.Println("=======================================================")
	fmt.Println()

	// Create Small QR
	qrconfig := qrterminal.Config{
		Level:      qrterminal.L,
		Writer:     os.Stdout,

View on GitHub (pinned to 49183d7e8d)

Solutions

  1. Inspect opts.Proxy byte-for-byte (fmt %q) for hidden control characters
  2. Percent-encode special characters in proxy credentials (% -> %25)
  3. Test with the proxy setting empty to confirm login works without it, then fix the proxy value
  4. Centralize proxy validation in config loading so bad values fail at startup with a clear message

Example fix

// before
_, _, _, _, err := weixin.Login(ctx, weixin.LoginOpts{Proxy: rawProxy})

// after
if _, perr := url.Parse(rawProxy); perr != nil {
    return fmt.Errorf("fix proxy config: %w", perr)
}
_, _, _, _, err := weixin.Login(ctx, weixin.LoginOpts{Proxy: rawProxy})
Defensive patterns

Strategy: validation

Validate before calling

if _, err := url.Parse(opts.Proxy); err != nil {
    return fmt.Errorf("weixin login proxy misconfigured: %w", err)
}
// only then start the interactive login flow

Type guard

func isWeixinClientCreateFail(err error) bool {
    return err != nil && strings.HasPrefix(err.Error(), "failed to create api client")
}

Try / catch

if _, _, _, _, err := weixin.Login(ctx, opts); err != nil {
    if isWeixinClientCreateFail(err) {
        // unwrap: almost always the proxy string; fix config, do not retry
    }
}

Prevention

When it happens

Trigger: Calling the interactive login entry point with opts.Proxy set to a string that fails url.Parse: control characters, NUL bytes, or an invalid percent-escape. BaseURL and BotType defaults are applied first (lines above), so those cannot cause it.

Common situations: Running headless login in CI with a proxy env var that contains a newline or unencoded credentials; a config template injecting a broken proxy value only in the login command path.

Related errors


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