cloudreve/cloudreve · warning
failed to unmarshal page token: %w
Error message
failed to unmarshal page token: %w
What it means
Second failure mode of pageTokenFromString: the string decodes as base64 but the bytes are not valid JSON for the PageToken struct (fields: time, id, string, int, start_with_file). Because PageToken is a struct (not a map), json.Unmarshal rejects syntactically invalid JSON immediately; semantically odd but well-formed JSON is accepted with unknown fields ignored. The ID field is tagged json:"-" so tokens minted by hand-crafting JSON cannot carry a raw numeric ID — only the hashid field 'id' is honored.
Source
Thrown at inventory/common.go:60
const (
OrderDirectionAsc = OrderDirection("asc")
OrderDirectionDesc = OrderDirection("desc")
)
var (
ErrTooManyArguments = fmt.Errorf("too many arguments")
)
func pageTokenFromString(s string, hasher hashid.Encoder, idType int) (*PageToken, error) {
sB64Decoded, err := base64.StdEncoding.DecodeString(s)
if err != nil {
return nil, fmt.Errorf("failed to decode base64 for page token: %w", err)
}
token := &PageToken{}
if err := json.Unmarshal(sB64Decoded, token); err != nil {
return nil, fmt.Errorf("failed to unmarshal page token: %w", err)
}
id, err := hasher.Decode(token.IDHash, idType)
if err != nil {
return nil, fmt.Errorf("failed to decode id: %w", err)
}
if token.Time == nil {
token.Time = &time.Time{}
}
token.ID = id
return token, nil
}
func (p *PageToken) Encode(hasher hashid.Encoder, encodeFunc hashid.EncodeFunc) (string, error) {
p.IDHash = encodeFunc(hasher, p.ID)
res, err := json.Marshal(p)View on GitHub (pinned to 20c95ad73f)
Solutions
- Only use tokens issued by the same deployment in the same API version: take next_token from the previous response and feed it back verbatim.
- Pre-validate client-side: base64-decode then json.Valid(bytes) before sending; if invalid, restart from page one.
- Do not cache page tokens across upgrades; after a Cloudreve upgrade, drop stored tokens and re-list from the beginning.
- If you maintain a fork that changed PageToken fields, version the token (e.g. prefix v1:) so mismatches are detectable.
Example fix
// before: hand-crafted token
raw, _ := json.Marshal(map[string]any{"page": 3})
token := base64.StdEncoding.EncodeToString(raw)
res, err := client.List(ctx, &inventory.ListDavAccountArgs{PageToken: token})
// after: use the server-issued cursor only
res, err := client.List(ctx, &inventory.ListDavAccountArgs{PageToken: prevRes.PaginationResults.NextPageToken}) Defensive patterns
Strategy: validation
Validate before calling
// Full client-side structural pre-check
func validPageToken(s string) bool {
raw, err := base64.StdEncoding.DecodeString(s)
if err != nil || !json.Valid(raw) {
return false
}
var probe map[string]any
return json.Unmarshal(raw, &probe) == nil
}
if args.PageToken != "" && !validPageToken(args.PageToken) {
args.PageToken = ""
} Type guard
func isPageTokenShapeError(err error) bool {
return err != nil && strings.Contains(err.Error(), "failed to unmarshal page token")
} Try / catch
if err != nil && isPageTokenShapeError(err) {
return apiError(400, "stale or malformed page token; restart pagination")
} Prevention
- Only replay tokens from the same deployment and API version.
- Drop persisted page tokens after upgrading the server.
- Prefer restarting from page one over repairing tokens by hand.
When it happens
Trigger: Passing base64 of a non-JSON payload ("aGVsbG8=" for "hello"), a JSON array, or a JSON object from a different application's pagination scheme; tokens generated by a different Cloudreve version whose PageToken JSON schema is incompatible; hand-constructed tokens attempting to bypass cursor pagination.
Common situations: Integrations that reuse another service's opaque-cursor format; scripts that base64-encode arbitrary JSON hoping to synthesize a page pointer; version skew between the token issuer and consumer (e.g. token cached long-term across an upgrade that changed token fields).
Related errors
- failed to decode base64 for page token: %w
- invalid page token %q: %w
- failed to decode id: %w
- failed to marshal page token: %w
- failed to unmarshal options for group %q: %w
AI-assisted analysis of cloudreve/cloudreve@20c95ad73f (2026-08-16).
Data as JSON: /api/errors/276619fef11732ea.
Report an issue: GitHub.