Tencent/WeKnora · error

no resource IDs (book IDs) configured

Error message

no resource IDs (book IDs) configured

What it means

FetchIncremental requires config.ResourceIDs to list which Yuque books (repos) to sync. This error is thrown when ResourceIDs is empty, since incremental sync has no defined scope of books to walk. It is a configuration guard, not an API failure.

Source

Thrown at internal/datasource/connector/yuque/connector.go:324

// Namespace may be empty on some responses; fall back to base URL only.
func buildDocURL(baseURL, namespace, slug string) string {
	if namespace == "" {
		return baseURL
	}
	return baseURL + "/" + namespace + "/" + slug
}

// FetchIncremental returns items changed (or deleted) since the prior cursor.
// Deletion detection: docs present in the prior cursor but absent from the
// current list are emitted as IsDeleted=true placeholder items.
func (c *Connector) FetchIncremental(
	ctx context.Context,
	config *types.DataSourceConfig,
	cursor *types.SyncCursor,
) ([]types.FetchedItem, *types.SyncCursor, error) {
	resourceIDs := config.ResourceIDs
	if len(resourceIDs) == 0 {
		return nil, nil, fmt.Errorf("no resource IDs (book IDs) configured")
	}

	// Decode prior cursor (if any).
	var prev *yuqueCursor
	if cursor != nil && cursor.ConnectorCursor != nil {
		var p yuqueCursor
		b, _ := json.Marshal(cursor.ConnectorCursor)
		_ = json.Unmarshal(b, &p)
		prev = &p
	}

	items, newCursor, err := c.walk(ctx, config, resourceIDs, prev, true)
	if err != nil {
		return nil, nil, err
	}

	// Marshal newCursor into a generic map for the SyncCursor wrapper.
	cursorMap := make(map[string]interface{})

View on GitHub (pinned to 988cbb0330)

Solutions

  1. Configure ResourceIDs in the datasource config with the numeric Yuque book IDs to sync
  2. Re-run the datasource setup/resource selection flow and save at least one book
  3. If syncing all repos is intended, populate ResourceIDs from ListResources results instead of leaving it empty
  4. Validate config on save (reject empty ResourceIDs) so the error surfaces at configuration time

Example fix

// before
config := &types.DataSourceConfig{Name: "yuque"} // ResourceIDs empty
// after
config := &types.DataSourceConfig{Name: "yuque", ResourceIDs: []string{"12345", "67890"}}
Defensive patterns

Strategy: validation

Validate before calling

func validateYuqueConfig(cfg *types.DataSourceConfig) error {
    if cfg == nil || len(cfg.ResourceIDs) == 0 {
        return fmt.Errorf("yuque datasource requires at least one numeric book ID in ResourceIDs")
    }
    return nil
}

Type guard

func hasResourceIDs(cfg *types.DataSourceConfig) bool {
    return cfg != nil && len(cfg.ResourceIDs) > 0
}

Try / catch

items, cur, err := ds.FetchIncremental(ctx, cfg, cursor)
if err != nil {
    if strings.Contains(err.Error(), "no resource IDs") {
        // recover by re-running resource selection / listing repos first
        cfg.ResourceIDs, err = selectBookIDs(ctx, cfg)
        if err != nil {
            return err
        }
        items, cur, err = ds.FetchIncremental(ctx, cfg, cursor)
    }
    if err != nil {
        return err
    }
}

Prevention

When it happens

Trigger: A DataSourceConfig is passed to FetchIncremental with ResourceIDs nil or length 0 — e.g. the datasource was created without selecting any books, or ResourceIDs was cleared by a config update.

Common situations: Connector registered without completing the resource-selection step; admin cleared the book selection in the datasource UI; config deserialization dropped an empty/missing resource_ids field.

Related errors


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