{"record":{"id":"5380ee777d0c4923","repo":"gastownhall/beads","slug":"parse-data-source-query-response-w","errorCode":null,"errorMessage":"parse data source query response: %w","messagePattern":"parse data source query response: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/notion/client.go","lineNumber":138,"sourceCode":"func (c *Client) QueryDataSource(ctx context.Context, dataSourceID string) ([]Page, error) {\n\tvar pages []Page\n\tvar cursor string\n\tfor pageNum := 0; pageNum < maxQueryPages; pageNum++ {\n\t\trequest := map[string]interface{}{\n\t\t\t\"page_size\":   maxPageSize,\n\t\t\t\"result_type\": \"page\",\n\t\t}\n\t\tif cursor != \"\" {\n\t\t\trequest[\"start_cursor\"] = cursor\n\t\t}\n\n\t\tbody, err := c.doRequest(ctx, http.MethodPost, \"/data_sources/\"+url.PathEscape(dataSourceID)+\"/query\", request)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tvar resp QueryDataSourceResponse\n\t\tif err := json.Unmarshal(body, &resp); err != nil {\n\t\t\treturn nil, fmt.Errorf(\"parse data source query response: %w\", err)\n\t\t}\n\t\tpages = append(pages, resp.Results...)\n\t\tif !resp.HasMore || resp.NextCursor == \"\" {\n\t\t\treturn pages, nil\n\t\t}\n\t\tcursor = resp.NextCursor\n\t}\n\treturn nil, fmt.Errorf(\"query pagination exceeded %d pages\", maxQueryPages)\n}\n\nfunc (c *Client) CreatePage(ctx context.Context, dataSourceID string, properties map[string]interface{}) (*Page, error) {\n\trequest := map[string]interface{}{\n\t\t\"parent\": map[string]interface{}{\n\t\t\t\"type\":           \"data_source_id\",\n\t\t\t\"data_source_id\": dataSourceID,\n\t\t},\n\t\t\"properties\": properties,\n\t}","sourceCodeStart":120,"sourceCodeEnd":156,"githubUrl":"https://github.com/gastownhall/beads/blob/71377f276968b452ee607177637970a4ff888584/internal/notion/client.go#L120-L156","documentation":"QueryDataSource POSTs to /data_sources/{id}/query and json.Unmarshals the response body into QueryDataSourceResponse. This error wraps any unmarshal failure, meaning the Notion API returned a 200 body that does not match the expected pagination envelope (has_more, next_cursor, results). It indicates a response-shape mismatch rather than an HTTP failure.","triggerScenarios":"Calling Client.QueryDataSource when the Notion API returns JSON that cannot unmarshal into QueryDataSourceResponse — e.g. an API version change renaming fields, a proxy/gateway returning HTML or an error page with 200 status, or types/properties fields in results not matching the Page/DataSource struct tags.","commonSituations":"Notion API version upgrades changing field names or types; corporate proxies or WAFs injecting non-JSON bodies; overly strict Go struct tags in the notion package after a library update; intermittent gateway errors returning HTML error pages.","solutions":["Log the raw response body (resp body from doRequest) to see what actually came back before the unmarshal failed.","Pin/verify the Notion-Version header matches the API version the structs were written for.","Check for a proxy or gateway rewriting responses (content-type should be application/json).","Update the notion client package so QueryDataSourceResponse matches the current Notion API schema.","Retry once on transient mismatch if the body looks like a gateway error page."],"exampleFix":"// before\nvar resp QueryDataSourceResponse\nif err := json.Unmarshal(body, &resp); err != nil {\n    return nil, fmt.Errorf(\"parse data source query response: %w\", err)\n}\n// after\nvar resp QueryDataSourceResponse\nif err := json.Unmarshal(body, &resp); err != nil {\n    return nil, fmt.Errorf(\"parse data source query response: %w (body: %.200s)\", err, body)\n}","handlingStrategy":"try-catch","validationCode":"if !strings.Contains(httpRes.Header.Get(\"Content-Type\"), \"application/json\") {\n    return fmt.Errorf(\"expected JSON response, got %q\", httpRes.Header.Get(\"Content-Type\"))\n}","typeGuard":null,"tryCatchPattern":"pages, err := client.QueryDataSource(ctx, dsID, query)\nif err != nil {\n    if strings.Contains(err.Error(), \"parse data source query response\") {\n        // log raw body / flag API-shape drift, retry once\n    }\n    return err\n}","preventionTips":["Pin the Notion-Version header your library was built against","Keep the notion client package updated with API schema changes","Log raw response bodies on decode failure for diagnostics","Reject non-JSON content types before unmarshalling"],"tags":["notion","json","api","response-parsing"],"backgroundTag":"json-unmarshal-failed","analyzedSha":"71377f276968b452ee607177637970a4ff888584","analyzedAt":"2026-08-30T18:55:39.744Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}