Tencent/WeKnora · error
unmarshal block children response: %w
Error message
unmarshal block children response: %w
What it means
GetBlockChildrenFlat received a 2xx response from /v1/blocks/{id}/children but json.Unmarshal into paginatedResponse failed — the body isn't the expected {results, has_more, next_cursor} envelope. The HTTP call succeeded (doRequest returned no error), so this is purely a response-shape problem.
Source
Thrown at internal/datasource/connector/notion/client.go:254
// fetching the full block tree content.
func (c *notionClient) GetBlockChildrenFlat(ctx context.Context, blockID string) ([]notionBlock, error) {
var allBlocks []notionBlock
var startCursor string
for {
path := fmt.Sprintf("/v1/blocks/%s/children", blockID)
if startCursor != "" {
path += "?start_cursor=" + startCursor
}
respBody, err := c.doRequest(ctx, http.MethodGet, path, nil)
if err != nil {
return nil, fmt.Errorf("get block children for %s: %w", blockID, err)
}
var resp paginatedResponse
if err := json.Unmarshal(respBody, &resp); err != nil {
return nil, fmt.Errorf("unmarshal block children response: %w", err)
}
var blocks []notionBlock
if err := json.Unmarshal(resp.Results, &blocks); err != nil {
return nil, fmt.Errorf("unmarshal blocks: %w", err)
}
allBlocks = append(allBlocks, blocks...)
if !resp.HasMore || resp.NextCursor == "" {
break
}
startCursor = resp.NextCursor
}
return allBlocks, nil
}
View on GitHub (pinned to 988cbb0330)
Solutions
- Log the raw respBody on failure — HTML indicates a proxy/interception problem, odd JSON indicates schema drift.
- Verify baseURL points at api.notion.com (or a transparent proxy) and TLS is not being intercepted without proper CA trust.
- Check paginatedResponse struct tags against the current Notion API pagination envelope; update if the API version changed.
- Ensure the block ID in the path didn't get mangled (a bad URL would normally 404, but a misconfigured gateway could 200 with an error page).
Defensive patterns
Strategy: type-guard
Type guard
func isLikelyJSON(b []byte) bool {
t := bytes.TrimSpace(b)
return len(t) > 0 && (t[0] == '{' || t[0] == '[')
} Try / catch
blocks, err := client.GetBlockChildrenFlat(ctx, blockID)
if err != nil && strings.HasPrefix(err.Error(), "unmarshal block children response:") {
// 200-but-not-JSON or envelope drift: inspect raw body, verify baseURL
return fmt.Errorf("malformed children response for %s: %w", blockID, err)
} Prevention
- Route directly to api.notion.com without response-rewriting proxies
- Keep paginatedResponse struct tags matched to the pinned API version
- Log raw bodies on unmarshal failures to distinguish HTML vs schema drift
- Validate fixtures against the live API in CI before releases
When it happens
Trigger: The children endpoint returns non-JSON (proxy HTML with 200 status) or a JSON body whose results/has_more/next_cursor fields have incompatible types (e.g. results as an object instead of array). Fired per pagination iteration.
Common situations: Intercepting proxy or captive portal returning 200 HTML; Notion API version bump changing the pagination envelope; mock/test servers with outdated fixtures; corrupted transfer encoding handled incorrectly by an intermediary.
Understand the failure class
Background: "failed to unmarshal" / json.Unmarshal errors: why parsing a response into a Go struct fails and how to fix it — this error's family across 23 libraries.
Related errors
- unmarshal page: %w
- unmarshal database: %w
- unmarshal data_source: %w
- unmarshal paginated response: %w
- unmarshal page results: %w
AI-assisted analysis of Tencent/WeKnora@988cbb0330 (2026-09-02).
Data as JSON: /api/errors/514c0247f8943a66.
Report an issue: GitHub.