Tencent/WeKnora · error
create download request: %w
Error message
create download request: %w
What it means
DownloadFile builds the attachment download with http.NewRequestWithContext(ctx, GET, fileURL, nil); if http.NewRequestWithContext fails (it only fails on malformed URLs or a nil context), the error is wrapped as 'create download request'. Since the URL already passed SSRF validation, this almost always means the URL string itself is not parseable as an absolute http(s) URL.
Source
Thrown at internal/datasource/connector/notion/client.go:387
}
var block notionBlock
if err := json.Unmarshal(respBody, &block); err != nil {
return nil, fmt.Errorf("unmarshal block: %w", err)
}
return &block, nil
}
const maxDownloadSize = 100 * 1024 * 1024 // 100MB — prevent OOM from oversized files
// DownloadFile downloads a file from the given URL (typically an S3 signed URL).
// Does not go through the rate limiter since it's not a Notion API call.
func (c *notionClient) DownloadFile(ctx context.Context, fileURL string) ([]byte, error) {
if err := utils.ValidateURLForSSRF(fileURL); err != nil {
return nil, fmt.Errorf("attachment URL rejected: %w", err)
}
req, err := http.NewRequestWithContext(ctx, http.MethodGet, fileURL, nil)
if err != nil {
return nil, fmt.Errorf("create download request: %w", err)
}
var lastErr error
for attempt := 0; attempt <= maxRetries; attempt++ {
resp, err := c.httpClient.Do(req)
if err != nil {
lastErr = err
if attempt < maxRetries {
if sErr := sleepWithContext(ctx, time.Duration(1<<attempt)*time.Second); sErr != nil {
return nil, sErr
}
continue
}
break
}
if resp.StatusCode != http.StatusOK {
resp.Body.Close()View on GitHub (pinned to 988cbb0330)
Solutions
- Log the exact fileURL value in the wrapped error context and run url.Parse on it locally to see the parse failure.
- Ensure the URL is absolute with an http/https scheme; re-fetch the block (ResolveBlock) to get Notion's canonical signed URL instead of a stored/reconstructed one.
- Guard the call site: skip downloading when the block's file URL field is empty rather than passing "".
- Trim whitespace and reject empty/relative strings before calling DownloadFile.
Example fix
// before
client.DownloadFile(ctx, strings.TrimSpace(attachment.Path)) // "s3/bucket/file.pdf"
// after
if u, err := url.Parse(attachment.Path); err != nil || u.Scheme == "" {
return fmt.Errorf("invalid attachment url %q", attachment.Path)
}
client.DownloadFile(ctx, attachment.Path) Defensive patterns
Strategy: validation
Validate before calling
func validateDownloadURL(raw string) error {
u, err := url.Parse(strings.TrimSpace(raw))
if err != nil {
return fmt.Errorf("unparsable attachment url: %w", err)
}
if u.Scheme == "" || u.Host == "" {
return fmt.Errorf("attachment url must be absolute: %q", raw)
}
return nil
} Type guard
func isAbsoluteHTTPURL(raw string) bool {
u, err := url.Parse(raw)
return err == nil && (u.Scheme == "http" || u.Scheme == "https") && u.Host != ""
} Try / catch
data, err := client.DownloadFile(ctx, fileURL)
if err != nil {
if strings.Contains(err.Error(), "create download request") {
logger.Warnf(ctx, "malformed attachment url %q; re-fetching block", fileURL)
return downloadAfterResolve(ctx, blockID)
}
return err
} Prevention
- Always take the file URL verbatim from the Notion block payload — never store a truncated or scheme-stripped version.
- Skip attachments with empty URL fields instead of passing "" to DownloadFile.
- Trim whitespace and reject relative paths at your ingestion boundary.
When it happens
Trigger: Calling DownloadFile with a URL missing its scheme (e.g. "s3/bucket/file.pdf" or "/files/doc.pdf"), containing spaces or control characters, or otherwise unparsable by net/url. Also fires if ctx is nil.
Common situations: Storing attachment URLs in a database that stripped the https:// prefix; hand-built relative paths from a mirror config; template output with whitespace/quotes embedded in the URL; passing an empty string when the block's file URL field was absent.
Understand the failure class
Background: "Invalid URL" errors: why new URL(), URI.parse, and reqwest::Url reject your string — missing scheme, whitespace, and bad path format — this error's family across 39 libraries.
Related errors
- download failed with status %d
- download file: %w
- create verification request failed: %w
- unmarshal block: %w
- attachment URL rejected: %w
AI-assisted analysis of Tencent/WeKnora@988cbb0330 (2026-09-02).
Data as JSON: /api/errors/aef678c387c68bca.
Report an issue: GitHub.