Tencent/WeKnora · error

invalid book id

Error message

invalid book id %q: %w

What it means

In walk, each configured resource ID must be a Yuque book (repo) numeric ID. This error is thrown when strconv.ParseInt fails on a configured resource ID string, meaning the datasource config contains a book ID that is not a plain integer. The %q preserves the offending value and %w preserves strconv's parse error (e.g. invalid syntax or value out of range).

Solutions

  1. Open the repo in Yuque and copy the numeric book ID from the URL or API (GET /api/v2/users/{login}/repos returns numeric id fields)
  2. Remove whitespace/quotes around the ID in the datasource config
  3. Replace any slug/namespace values in ResourceIDs with the corresponding numeric IDs
  4. Log config.ResourceIDs at startup to catch malformed entries before walking

Example fix

// before
resourceIDs: ["my-team/my-wiki", " 12345 "]
// after
resourceIDs: ["12345"] // numeric book IDs only, no slugs or spaces
Defensive patterns

Strategy: validation

Validate before calling

func validBookIDs(ids []string) error {
    for _, id := range ids {
        if _, err := strconv.ParseInt(strings.TrimSpace(id), 10, 64); err != nil {
            return fmt.Errorf("book id %q is not a numeric yuque book id", id)
        }
    }
    return nil
}

Type guard

func isNumericBookID(s string) bool {
    _, err := strconv.ParseInt(s, 10, 64)
    return err == nil
}

Try / catch

items, _, err := ds.Fetch(ctx, cfg, cursor)
if err != nil {
    var pe *strconv.NumError
    if errors.As(err, &pe) {
        return fmt.Errorf("fix ResourceIDs: contains non-numeric value: %v", err)
    }
    return err
}

Prevention

When it happens

Trigger: config.ResourceIDs contains a non-numeric string — e.g. a repo slug like "my-wiki", a URL copied from the browser containing a namespace, whitespace, or a value exceeding int64 range.

Common situations: User pasted a repo namespace (login/slug) instead of the numeric ID; copied the ID with trailing spaces or quotes; used a slug-based config from an older connector version that accepted slugs.

Related errors


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

Appendix: source

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

	ctx context.Context,
	config *types.DataSourceConfig,
	resourceIDs []string,
	prev *yuqueCursor,
	incremental bool,
) ([]types.FetchedItem, *yuqueCursor, error) {
	cfg, err := parseYuqueConfig(config)
	if err != nil {
		return nil, nil, err
	}
	cli := newClient(cfg)

	newCursor := &yuqueCursor{LastSyncTime: time.Now(), BookDocTimes: make(map[string]map[string]string)}
	var out []types.FetchedItem

	for _, bookIDStr := range resourceIDs {
		bookID, err := strconv.ParseInt(bookIDStr, 10, 64)
		if err != nil {
			return nil, nil, fmt.Errorf("invalid book id %q: %w", bookIDStr, err)
		}

		docs, err := cli.ListBookDocs(ctx, bookID)
		if err != nil {
			return nil, nil, fmt.Errorf("list docs for book %d: %w", bookID, err)
		}

		currentDocs := make(map[string]bool)
		newCursor.BookDocTimes[bookIDStr] = make(map[string]string)

		var skippedType, skippedDraft, kept int
		var sampleSkipType, sampleSkipDraft string
		for _, d := range docs {
			// Empty type/status is treated as acceptable — forward-compat with
			// API variations that omit the field.
			if d.Type != "" && d.Type != "Doc" {
				skippedType++
				if sampleSkipType == "" {

View on GitHub (pinned to 988cbb0330)