Tencent/WeKnora · error
database %s has no data sources
Error message
database %s has no data sources
What it means
QueryDatabaseAll queries a Notion database by trying the id as a data_source_id first; on 404 it falls back to treating the id as a database container ID and resolves it via GET /v1/databases/{id}. If that database object exists but its data_sources list is empty (info.DataSourceID == ""), the client cannot identify any data source to POST /v1/data_sources/{id}/query against, so it throws this error. In practice this means the id is a valid database container but Notion's API model exposes no queryable data source for it (API-version drift or an empty/deleted database).
Source
Thrown at internal/datasource/connector/notion/client.go:357
}
// QueryDatabaseAll retrieves all records from a database via POST /v1/data_sources/{id}/query.
// Accepts either a data_source_id (from search) or a database_id (from child_database blocks).
// For database_ids, resolves to data_source_id via GET /v1/databases/{id}.
func (c *notionClient) QueryDatabaseAll(ctx context.Context, id string) ([]notionPage, error) {
// Try as data_source_id directly
records, err := c.paginatePages(ctx, http.MethodPost, fmt.Sprintf("/v1/data_sources/%s/query", id))
if err == nil {
return records, nil
}
// If 404, id might be a database container ID — resolve to data_source_id
info, dbErr := c.GetDatabaseInfo(ctx, id)
if dbErr != nil {
return nil, fmt.Errorf("query database %s: not a data_source (%v) and not a database (%v)", id, err, dbErr)
}
if info.DataSourceID == "" {
return nil, fmt.Errorf("database %s has no data sources", id)
}
return c.paginatePages(ctx, http.MethodPost, fmt.Sprintf("/v1/data_sources/%s/query", info.DataSourceID))
}
// ResolveBlock re-fetches a single block to resolve file_upload URLs.
// When a block contains a file_upload type, re-fetching it returns the resolved
// download URL (temporary S3 signed URL, 1-hour expiry).
func (c *notionClient) ResolveBlock(ctx context.Context, blockID string) (*notionBlock, error) {
respBody, err := c.doRequest(ctx, http.MethodGet, "/v1/blocks/"+blockID, nil)
if err != nil {
return nil, err
}
var block notionBlock
if err := json.Unmarshal(respBody, &block); err != nil {
return nil, fmt.Errorf("unmarshal block: %w", err)
}
return &block, nil
}View on GitHub (pinned to 988cbb0330)
Solutions
- Re-fetch the database id from the Notion search endpoint or a fresh child_database block to get a current data_source_id and pass that to QueryDatabaseAll.
- Open the database in Notion and confirm it still contains at least one data source (not deleted/emptied); restore or recreate it if so.
- If you control the integration, pin a Notion API version where databases still expose data_sources, or update notionBlock/notionDatabase parsing so DataSourceID is extracted from the new response shape.
- Check that GetDatabaseInfo unmarshals the data_sources array correctly — an empty DataSourceID may indicate a struct-field mismatch (e.g. wrong JSON tag) rather than a truly empty database.
Example fix
// before records, err := client.QueryDatabaseAll(ctx, "a1b2c3d4e5f6..." ) // old cached database container id // after dataSourceID := "f6e5d4c3b2a1..." // from search result or block data_source.id records, err := client.QueryDatabaseAll(ctx, dataSourceID)
Defensive patterns
Strategy: validation
Validate before calling
if id == "" {
return fmt.Errorf("database id is required")
}
// prefer data_source ids obtained from search / child_database blocks:
if !strings.Contains(id, "data_source") && dataSourceID != "" {
id = dataSourceID
} Type guard
func hasDataSource(info *notionDatabaseInfo) bool {
return info != nil && info.DataSourceID != ""
} Try / catch
records, err := client.QueryDatabaseAll(ctx, id)
if err != nil {
if strings.Contains(err.Error(), "has no data sources") {
// fall back to re-resolving the id via search or skip the database
logger.Warnf(ctx, "skipping database %s: no data sources", id)
return nil
}
return err
} Prevention
- Store and pass data_source_id (not the database container id) whenever the API surface provides one.
- Re-resolve ids from search/blocks instead of caching database ids across long-lived jobs.
- Before querying, call GetDatabaseInfo and check DataSourceID != "" to fail fast with a clearer message.
When it happens
Trigger: Calling QueryDatabaseAll(ctx, id) where id is a database container ID (e.g. from a child_database block) whose GET /v1/databases/{id} response has an empty data_sources array — i.e. info.DataSourceID is empty. Requires the initial data_source query attempt to have failed with 404 first.
Common situations: Using an old database_id cached before Notion moved querying to the data_sources endpoint (API version 2022-06-28 vs newer 2025-09-03-style layouts); the database was emptied/deleted so its only data source was removed; copying a database container URL id instead of the data_source id from search results.
Related errors
- unmarshal database: %w
- unmarshal data_sources: %w
- unmarshal data_source: %w
- failed to ensure FAQ knowledge: %w
- failed to create chunk: %w
AI-assisted analysis of Tencent/WeKnora@988cbb0330 (2026-09-02).
Data as JSON: /api/errors/61e5997ee42dd1c5.
Report an issue: GitHub.