{"record":{"id":"6c0b23b239176eee","repo":"Tencent/WeKnora","slug":"get-block-children-for-s-w","errorCode":null,"errorMessage":"get block children for %s: %w","messagePattern":"get block children for (.+?): %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/datasource/connector/notion/client.go","lineNumber":249,"sourceCode":"\treturn &ds, nil\n}\n\n// GetBlockChildrenFlat fetches only the direct children of a block (no recursion).\n// Used by discoverPages to quickly scan for child_page/child_database without\n// fetching the full block tree content.\nfunc (c *notionClient) GetBlockChildrenFlat(ctx context.Context, blockID string) ([]notionBlock, error) {\n\tvar allBlocks []notionBlock\n\tvar startCursor string\n\n\tfor {\n\t\tpath := fmt.Sprintf(\"/v1/blocks/%s/children\", blockID)\n\t\tif startCursor != \"\" {\n\t\t\tpath += \"?start_cursor=\" + startCursor\n\t\t}\n\n\t\trespBody, err := c.doRequest(ctx, http.MethodGet, path, nil)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"get block children for %s: %w\", blockID, err)\n\t\t}\n\n\t\tvar resp paginatedResponse\n\t\tif err := json.Unmarshal(respBody, &resp); err != nil {\n\t\t\treturn nil, fmt.Errorf(\"unmarshal block children response: %w\", err)\n\t\t}\n\n\t\tvar blocks []notionBlock\n\t\tif err := json.Unmarshal(resp.Results, &blocks); err != nil {\n\t\t\treturn nil, fmt.Errorf(\"unmarshal blocks: %w\", err)\n\t\t}\n\n\t\tallBlocks = append(allBlocks, blocks...)\n\n\t\tif !resp.HasMore || resp.NextCursor == \"\" {\n\t\t\tbreak\n\t\t}\n\t\tstartCursor = resp.NextCursor","sourceCodeStart":231,"sourceCodeEnd":267,"githubUrl":"https://github.com/Tencent/WeKnora/blob/988cbb03305e055d8ebb7d46d9ac6cc0803cd074/internal/datasource/connector/notion/client.go#L231-L267","documentation":"GetBlockChildrenFlat wraps any error from doRequest when fetching /v1/blocks/{blockID}/children. The wrapper adds the block ID for debugging; the underlying cause can be ErrInvalidCredentials (401/403), ErrResourceNotFound (404), rate limiting (429), 5xx, or network errors — all retried where applicable inside doRequest before this wrapper fires.","triggerScenarios":"doRequest fails for any of: 401/403 (token revoked or integration lacks access to the block), 404 (block deleted or wrong ID), exhausted 429 retries, exhausted 5xx retries, or transport failure — during any pagination iteration of the children loop. Also used by getBlockChildrenRecursive (same message at client.go:296).","commonSituations":"Integration not shared with the containing page (Notion requires explicit connection sharing → 404/403); block deleted between discovery and fetch; token rotated/revoked mid-sync; rate limits exhausted on large pages with many children pages.","solutions":["Read the wrapped cause: if 401/403, re-share the parent page with the integration in Notion (Settings → Connections).","If 404, verify the block ID — the block may be deleted or the integration lacks access to its ancestors.","In Notion, ensure all ancestor pages of the target are shared with the integration — Notion access is hierarchical.","For rate-limit causes, reduce sync concurrency or retry later (see rate-limit guidance).","Re-run Ping (/v1/users/me) to confirm the token is still valid."],"exampleFix":"// before: assume block exists\nblocks, err := client.GetBlockChildrenFlat(ctx, blockID)\nif err != nil { return err }\n// after: skip inaccessible/deleted blocks gracefully\nblocks, err := client.GetBlockChildrenFlat(ctx, blockID)\nif err != nil {\n    if errors.Is(err, datasource.ErrResourceNotFound) {\n        log.Printf(\"block %s gone or inaccessible, skipping\", blockID)\n        return nil, nil\n    }\n    return err\n}","handlingStrategy":"try-catch","validationCode":"// Verify access + token before fetching children\nif err := client.Ping(ctx); err != nil {\n    return fmt.Errorf(\"invalid or revoked token: %w\", err)\n}\n// Note: share the page containing the block with the integration in Notion UI first.","typeGuard":null,"tryCatchPattern":"blocks, err := client.GetBlockChildrenFlat(ctx, blockID)\nswitch {\ncase errors.Is(err, datasource.ErrInvalidCredentials):\n    // re-share page with integration / rotate token\ncase errors.Is(err, datasource.ErrResourceNotFound):\n    // block deleted or not shared: skip gracefully\ncase strings.Contains(err.Error(), \"rate limited\"):\n    // back off and retry\n}","preventionTips":["Share every top-level page (and thus its ancestors) with the integration before syncing","Handle ErrResourceNotFound as a skip, not a fatal sync error","Re-run Ping when 401/403 errors start appearing — token may have been rotated","Throttle bulk traversals to avoid 429 exhaustion on child-heavy pages"],"tags":["notion","block-children","api-error","permissions","wrapped-error"],"backgroundTag":"notion-block-access-denied","analyzedSha":"988cbb03305e055d8ebb7d46d9ac6cc0803cd074","analyzedAt":"2026-09-02T14:41:08.344Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}