Tencent/WeKnora · warning

invalid cursor %q

Error message

invalid cursor %q

What it means

GetIndexView parses the opaque pagination cursor as a non-negative integer offset. If the cursor is non-numeric or negative, the service rejects it with 'invalid cursor %q' instead of guessing a default. This is a strict input-validation guard for paginated wiki index views.

Source

Thrown at internal/application/service/wiki_page.go:488

	limit int,
	cursor string,
) (*types.WikiIndexResponse, error) {
	indexPage, err := s.GetIndex(ctx, kbID)
	if err != nil {
		return nil, fmt.Errorf("load index page: %w", err)
	}

	if limit <= 0 {
		limit = 50
	}
	if limit > 200 {
		limit = 200
	}
	offset := 0
	if cursor != "" {
		v, parseErr := strconv.Atoi(cursor)
		if parseErr != nil || v < 0 {
			return nil, fmt.Errorf("invalid cursor %q", cursor)
		}
		offset = v
	}

	// Default to every known content type when the caller passes no
	// filter. Any unknown request-time type is passed through verbatim so
	// future page types (declared in types/wiki_page.go) start showing
	// up in the index the moment the LLM starts creating them, without a
	// handler change.
	selected := pageTypes
	if len(selected) == 0 {
		selected = append([]string{}, wikiIndexContentPageTypes...)
	}

	groups := make([]types.WikiIndexGroup, 0, len(selected))
	for _, pt := range selected {
		entries, total, listErr := s.repo.ListByTypeLight(ctx, kbID, pt, limit, offset)
		if listErr != nil {

View on GitHub (pinned to 988cbb0330)

Solutions

  1. Pass only the exact cursor string previously returned by the API, or omit it entirely to start from offset 0.
  2. Strip whitespace and confirm the cursor is a non-negative integer before sending it.
  3. If migrating from a token-based cursor API, map old tokens to numeric offsets client-side before calling.
  4. Return a clear 400 to the end user prompting them to restart pagination from the first page.

Example fix

// before
GET /api/wiki/index?cursor=abc
// after
GET /api/wiki/index
// or resume with a valid offset
GET /api/wiki/index?cursor=200
Defensive patterns

Strategy: validation

Validate before calling

func validCursor(c string) bool {
    if c == "" { return true } // empty means start from beginning
    v, err := strconv.Atoi(strings.TrimSpace(c))
    return err == nil && v >= 0
}
if !validCursor(cursor) { cursor = "" }

Try / catch

entries, err := svc.GetIndexView(ctx, kbID, cursor)
if err != nil && strings.Contains(err.Error(), "invalid cursor") {
    entries, err = svc.GetIndexView(ctx, kbID, "") // restart pagination
}

Prevention

When it happens

Trigger: Calling GetIndexView (or the HTTP endpoint backed by it) with a cursor query parameter that is not a base-10 integer (e.g. cursor=abc, cursor='', base64/glyph cursors from a different API) or a negative number like cursor=-5.

Common situations: Clients sending cursors copied from another paginated API (page tokens vs numeric offsets); frontends echoing back mutated or truncated cursor strings; stale bookmarks with hand-edited URLs; API version mismatches where cursor formats changed.

Related errors


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