Tencent/WeKnora · error

unmarshal page: %w

Error message

unmarshal page: %w

What it means

GetPage fetched a page successfully from /v1/pages/{id} but json.Unmarshal of the response into the notionPage struct failed. This indicates the response body is not valid JSON or its shape doesn't match notionPage's typed fields. The doRequest call itself succeeded, so auth and network were fine.

Source

Thrown at internal/datasource/connector/notion/client.go:174

	_, err := c.doRequest(ctx, http.MethodGet, "/v1/users/me", nil)
	return err
}

// SearchPages returns all pages and databases accessible to the integration.
func (c *notionClient) SearchPages(ctx context.Context) ([]notionPage, error) {
	return c.paginatePages(ctx, http.MethodPost, "/v1/search")
}

// GetPage retrieves a single page by ID.
func (c *notionClient) GetPage(ctx context.Context, pageID string) (*notionPage, error) {
	respBody, err := c.doRequest(ctx, http.MethodGet, "/v1/pages/"+pageID, nil)
	if err != nil {
		return nil, err
	}

	var page notionPage
	if err := json.Unmarshal(respBody, &page); err != nil {
		return nil, fmt.Errorf("unmarshal page: %w", err)
	}
	page.Title = extractTitle(&page)
	return &page, nil
}

// databaseInfo holds both the metadata and the data source ID from a single API call.
type databaseInfo struct {
	Page         notionPage
	DataSourceID string
}

// GetDatabaseInfo retrieves a database container by ID, returning both
// the page metadata and the primary data source ID in a single API call.
func (c *notionClient) GetDatabaseInfo(ctx context.Context, dbID string) (*databaseInfo, error) {
	respBody, err := c.doRequest(ctx, http.MethodGet, "/v1/databases/"+dbID, nil)
	if err != nil {
		return nil, err
	}

View on GitHub (pinned to 988cbb0330)

Solutions

  1. Print/log the raw respBody on failure to see what was actually returned — usually reveals HTML or unexpected JSON.
  2. Verify baseURL is https://api.notion.com (or a faithful proxy) and not intercepting with 200 responses.
  3. Pin NotionAPIVersion to a version compatible with the notionPage struct; update struct tags if you upgrade the API version.
  4. Check that no proxy injects content (disable HTTPS interception or trust the proxy's CA properly).
Defensive patterns

Strategy: type-guard

Type guard

func isLikelyJSON(b []byte) bool {
    t := bytes.TrimSpace(b)
    return len(t) > 0 && (t[0] == '{' || t[0] == '[')
}
// usage: if !isLikelyJSON(respBody) { /* proxy/HTML interference */ }

Try / catch

page, err := client.GetPage(ctx, pageID)
if err != nil && strings.HasPrefix(err.Error(), "unmarshal page:") {
    // log raw response via tracing middleware; suspect proxy or schema drift
    log.Printf("non-conforming page response: %v", err)
}

Prevention

When it happens

Trigger: GET /v1/pages/{pageID} returns a body that fails to decode into notionPage — e.g. an HTML error page from a proxy (2xx but not JSON), or a Notion response whose typed fields (created_time, last_edited_time, etc.) change shape in a new API version while Notion-Version header pins an older version.

Common situations: A reverse proxy or captive portal returning 200 with HTML instead of JSON; Notion API version drift changing response schemas; corrupted gzip/encoding handling by an intermediary; baseURL accidentally pointing at a non-Notion service that answers 200 with other content.

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


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