t8y2/dbx · error

Continuation does not match request

Error message

Continuation does not match request

What it means

listPrefix supports cursor-based pagination. A continuation token encodes the root path and whether listing is recursive (via decodeCursor). If the decoded cursor's Root or Recursive flag differs from the current request, the token cannot be applied to this query and 'Continuation does not match request' is returned.

Source

Thrown at agents/drivers/zookeeper/operations.go:292

		return listResponse{}, err
	}
	root := normalizePath(request.Prefix)
	recursive := true
	if request.Recursive != nil {
		recursive = *request.Recursive
	}
	limit := request.Limit
	if limit < 1 {
		limit = defaultListLimit
	}
	cursor := listCursor{Root: root, Recursive: recursive}
	if strings.TrimSpace(request.Continuation) != "" {
		decoded, err := decodeCursor(request.Continuation)
		if err != nil {
			return listResponse{}, err
		}
		if decoded.Root != root || decoded.Recursive != recursive {
			return listResponse{}, errors.New("Continuation does not match request")
		}
		cursor = decoded
	}
	exists, _, err := client.Exists(root)
	if err != nil {
		return listResponse{}, err
	}
	if !exists {
		return listResponse{Keys: []map[string]any{}, Continuation: nil}, nil
	}
	var paths []string
	if recursive {
		paths, err = listRecursive(client, root)
	} else {
		paths, err = listDirectChildren(client, root)
	}
	if err != nil {
		return listResponse{}, err

View on GitHub (pinned to c0390bff16)

Solutions

  1. Restart listing from the first page with the new parameters instead of passing the old continuation.
  2. Keep the root and Recursive flag identical across all pages of one listing loop.
  3. Generate a fresh token per listing session; never share tokens across different queries or users.
  4. If cursors are persisted client-side, include the request parameters alongside and discard the token when they change.

Example fix

// before
// page 2 request changed Recursive from true to false but reused token
cursor, err := driver.List(ctx, root, false, token)
// after
cursor, err := driver.List(ctx, root, true, token) // same params as page 1
// (or drop token: driver.List(ctx, root, false, ""))
Defensive patterns

Strategy: validation

Validate before calling

// Keep listing parameters stable across pages; reset the token when they change
func (p *Pager) TokenFor(root string, recursive bool) string {
    if p.root != root || p.recursive != recursive {
        return "" // parameters changed: start a fresh listing
    }
    return p.continuation
}

Try / catch

resp, err := driver.List(ctx, root, recursive, token)
if err != nil && strings.Contains(err.Error(), "Continuation does not match request") {
    token = "" // stale cursor: restart listing from the first page
    resp, err = driver.List(ctx, root, recursive, token)
}

Prevention

When it happens

Trigger: Calling listPrefix with a Continuation obtained from a different root path, or with a Recursive value different from the request that produced the token (e.g. token from a recursive list reused for a flat list, or from another prefix). Raised in agents/drivers/zookeeper/operations.go:292.

Common situations: Client-side pagination loop that changes the prefix or Recursive flag between pages; reusing a stored cursor after the user changed search parameters; mixing cursors between two concurrent lists; serialization bugs truncating/corrupting the cursor (though that usually errors in decodeCursor first).

Related errors


AI-assisted analysis of t8y2/dbx@c0390bff16 (2026-09-05). Data as JSON: /api/errors/368c6b82ce1fc23a. Report an issue: GitHub.