Tencent/WeKnora · error

invalid api_base_url: %w

Error message

invalid api_base_url: %w

What it means

Feishu's validateAPIBaseURL allows a custom api_base_url for private deployments, but first parses it with url.Parse. This error wraps any url.Parse failure, meaning the configured api_base_url is not a syntactically valid URL.

Source

Thrown at internal/im/feishu/adapter.go:100

		appID:             appID,
		appSecret:         appSecret,
		verificationToken: verificationToken,
		encryptKey:        encryptKey,
		apiBaseURL:        apiBaseURL,
	}, nil
}

// validateAPIBaseURL checks that a custom Feishu/Lark API base URL uses an
// http(s) scheme and passes SSRF validation. Empty or the region default is
// allowed without further checks. Mirrors wecom.validateEndpointURL but allows
// plain http for internal-network reverse proxies that terminate TLS at nginx.
func validateAPIBaseURL(endpoint, defaultEndpoint string) error {
	if endpoint == "" || endpoint == defaultEndpoint {
		return nil
	}
	u, err := url.Parse(endpoint)
	if err != nil {
		return fmt.Errorf("invalid api_base_url: %w", err)
	}
	if u.Scheme != "http" && u.Scheme != "https" {
		return fmt.Errorf("api_base_url must use http(s):// scheme, got %s://", u.Scheme)
	}
	if err := utils.ValidateURLForSSRF(endpoint); err != nil {
		return fmt.Errorf("%w (for private deployments on internal networks, add the hostname to SSRF_WHITELIST)", err)
	}
	return nil
}

// api builds an Open Platform API URL on this adapter's cloud. path is a format
// string beginning with "/open-apis/"; args fill its verbs.
func (a *Adapter) api(path string, args ...any) string {
	return a.apiBaseURL + fmt.Sprintf(path, args...)
}

// startStreamReaper starts a background goroutine (once) that periodically
// removes orphaned stream entries from feishuStreams. This prevents memory

View on GitHub (pinned to 988cbb0330)

Solutions

  1. Fix the wrapped url.Parse error — validate the string with net/url.Parse in a quick test to see the exact problem.
  2. Re-enter the api_base_url cleanly, e.g. https://open.feishu.internal, without quotes or stray whitespace.
  3. Leave api_base_url empty to use the default endpoint if a custom one isn't actually needed.

Example fix

// before
api_base_url: "https://open.feishu.cn/%zz"
// after
api_base_url: "https://open.feishu.cn"
Defensive patterns

Strategy: validation

Validate before calling

if endpoint != "" {
    if _, err := url.Parse(endpoint); err != nil {
        return fmt.Errorf("api_base_url is not a valid URL: %w", err)
    }
}

Type guard

func isParseableURL(s string) bool { _, err := url.Parse(s); return err == nil }

Try / catch

if err := validateAPIBaseURL(endpoint, defaultEndpoint); err != nil {
    if strings.HasPrefix(err.Error(), "invalid api_base_url") {
        return fmt.Errorf("fix api_base_url syntax: %w", err)
    }
    return err
}

Prevention

When it happens

Trigger: NewAdapter called with a custom endpoint (non-empty and different from the default) that url.Parse rejects — e.g. containing invalid characters, a bare '%' or malformed percent-encoding, or control characters.

Common situations: Copy-pasting a URL with trailing spaces/quotes or invisible characters; missing scheme typos that produce unparseable input; shell/env escaping introducing stray characters.

Understand the failure class

Background: "Invalid URL" / "URL cannot be empty": fix the malformed or missing URL behind request-construction failures — this error's family across 50 libraries.

Related errors


AI-assisted analysis of Tencent/WeKnora@988cbb0330 (2026-09-02). Data as JSON: /api/errors/1d70661d136b9edc. Report an issue: GitHub.