gastownhall/beads · error

resolve %q as data source: %w; as database: %v

Error message

resolve %q as data source: %w; as database: %v

What it means

ResolveDataSourceReference tries RetrieveDataSource first; on failure it falls back to RetrieveDatabase. If the database lookup also fails it returns this combined error carrying both the data-source error (%w, unwrap target) and the database error (%v). It means the identifier matched neither a data source nor a database the token can read.

Source

Thrown at internal/notion/client.go:224

func ResolveDataSourceReference(ctx context.Context, client DataSourceResolver, ref string) (*ResolvedDataSource, error) {
	if client == nil {
		return nil, fmt.Errorf("notion client is nil")
	}
	identifier := ExtractNotionIdentifier(ref)
	if identifier == "" {
		return nil, fmt.Errorf("could not extract a Notion ID from %q", ref)
	}
	if ds, err := client.RetrieveDataSource(ctx, identifier); err == nil {
		return &ResolvedDataSource{
			InputID:      identifier,
			DataSourceID: ds.ID,
			DataSource:   ds,
			ViewURL:      strings.TrimSpace(ref),
		}, nil
	} else {
		db, dbErr := client.RetrieveDatabase(ctx, identifier)
		if dbErr != nil {
			return nil, fmt.Errorf("resolve %q as data source: %w; as database: %v", ref, err, dbErr)
		}
		if len(db.DataSources) == 0 || strings.TrimSpace(db.DataSources[0].ID) == "" {
			return nil, fmt.Errorf("database %s has no child data sources", db.ID)
		}
		resolvedID := strings.TrimSpace(db.DataSources[0].ID)
		resolvedDS, err := client.RetrieveDataSource(ctx, resolvedID)
		if err != nil {
			return nil, fmt.Errorf("retrieve child data source %s: %w", resolvedID, err)
		}
		return &ResolvedDataSource{
			InputID:      identifier,
			DataSourceID: resolvedID,
			DataSource:   resolvedDS,
			Database:     db,
			ViewURL:      strings.TrimSpace(ref),
		}, nil
	}
}

View on GitHub (pinned to 71377f2769)

Solutions

  1. Open Notion → Connections and share the database (not just the parent page) with the integration.
  2. Verify the ID resolves in the browser and is actually a database/data source, not a plain page.
  3. Check the token is for the correct workspace and has not been revoked; re-issue if needed.
  4. Read the wrapped errors separately (errors.Unwrap / the 'as database:' suffix) to distinguish 401 (permissions) from 404 (wrong object).

Example fix

// before
resolved, err := notion.ResolveDataSourceReference(ctx, client, pageIDFromConfig) // page, not database
// after
// set the config value to the database/data source URL shared with the integration
resolved, err := notion.ResolveDataSourceReference(ctx, client, databaseURLSharedWithIntegration)
Defensive patterns

Strategy: validation

Validate before calling

// before resolving, confirm the integration can see the resource:
// 1. open the link in a browser as the workspace admin
// 2. check Notion -> Connections includes the integration on the database

Try / catch

resolved, err := notion.ResolveDataSourceReference(ctx, client, ref)
if err != nil {
    var apiErr *notion.APIError
    if errors.As(err, &apiErr) && apiErr.Status == 401 {
        // permissions problem: share the resource with the integration
    }
    return err
}

Prevention

When it happens

Trigger: Calling ResolveDataSourceReference with an ID that is neither a data source nor a database (e.g. a page ID), or with an ID the integration token cannot access — both RetrieveDataSource and RetrieveDatabase return 404/401.

Common situations: Sharing a page (not the database) with the integration; forgetting to grant the integration to the workspace/database; the referenced resource was deleted or moved; pointing at a regular page ID expecting database semantics.

Related errors


AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30). Data as JSON: /api/errors/10bb7a31ac3c0bb9. Report an issue: GitHub.