multica-ai/multica · warning
invalid limit
Error message
invalid limit
What it means
This error is returned by parseChatMessagesPageParams when the optional `limit` query parameter on the chat messages listing endpoint fails to parse as an integer, or parses to a value outside the allowed 1..100 window. The server defaults to 50 when the parameter is absent, so the error only fires on a malformed or out-of-range explicit value. It exists to cap page size and prevent non-numeric input from reaching the SQL query layer.
Source
Thrown at server/internal/handler/chat.go:994
type ChatMessagesCursorResponse struct {
CreatedAt string `json:"created_at"`
ID string `json:"id"`
}
type ChatMessagesPageResponse struct {
Messages []ChatMessageResponse `json:"messages"`
Limit int `json:"limit"`
HasMore bool `json:"has_more"`
NextCursor *ChatMessagesCursorResponse `json:"next_cursor,omitempty"`
}
func parseChatMessagesPageParams(r *http.Request) (int, pgtype.Timestamptz, pgtype.UUID, error) {
limit := 50
if raw := r.URL.Query().Get("limit"); raw != "" {
parsed, err := strconv.Atoi(raw)
if err != nil || parsed < 1 || parsed > 100 {
return 0, pgtype.Timestamptz{}, pgtype.UUID{}, errors.New("invalid limit")
}
limit = parsed
}
rawBeforeCreatedAt := r.URL.Query().Get("before_created_at")
rawBeforeID := r.URL.Query().Get("before_id")
if rawBeforeCreatedAt == "" && rawBeforeID == "" {
return limit, pgtype.Timestamptz{}, pgtype.UUID{}, nil
}
if rawBeforeCreatedAt == "" || rawBeforeID == "" {
return 0, pgtype.Timestamptz{}, pgtype.UUID{}, errors.New("invalid cursor")
}
beforeTime, err := time.Parse(time.RFC3339Nano, rawBeforeCreatedAt)
if err != nil {
return 0, pgtype.Timestamptz{}, pgtype.UUID{}, errors.New("invalid cursor")
}
beforeID, err := util.ParseUUID(rawBeforeID)
if err != nil {View on GitHub (pinned to 2c0912b6ec)
Solutions
- Clamp the requested limit client-side to the 1..100 range before building the URL (e.g. Math.min(Math.max(limit,1),100)).
- Omit the limit parameter entirely when you want the default of 50.
- Ensure the limit is serialized as an integer string, not a float or scientific-notation value.
- Treat the 400 response as non-retryable: fix the input, do not backoff-and-retry.
Example fix
// before
const url = `/api/chat/${id}/messages?limit=${userLimit}`;
// after
const clamped = Math.min(Math.max(Number(userLimit) || 50, 1), 100);
const url = `/api/chat/${id}/messages?limit=${clamped}`; Defensive patterns
Strategy: validation
Validate before calling
function buildMessagesUrl(chatId, { limit, cursor } = {}) {
const params = new URLSearchParams();
if (limit !== undefined) {
const n = Number(limit);
if (!Number.isInteger(n) || n < 1 || n > 100) {
throw new RangeError(`limit must be an integer in [1,100], got ${limit}`);
}
params.set('limit', String(n));
}
if (cursor) {
if (!cursor.created_at || !cursor.id) throw new TypeError('cursor requires both created_at and id');
params.set('before_created_at', cursor.created_at);
params.set('before_id', cursor.id);
}
return `/api/chat/${chatId}/messages${params.size ? '?' + params : ''}`;
} Type guard
const isValidLimit = (v) => Number.isInteger(v) && v >= 1 && v <= 100;
Prevention
- Centralize URL building for the messages endpoint in one helper so the clamp is applied everywhere.
- Treat HTTP 400 from this endpoint as a programming error — log and fix the caller, never retry.
- Keep the previous page's next_cursor opaque: store it verbatim instead of decomposing it.
When it happens
Trigger: GET /chat messages endpoint with `?limit=0`, `?limit=101`, `?limit=-5`, `?limit=abc`, or `?limit=50.5` (strconv.Atoi rejects floats). Any value that is not a base-10 integer in [1,100] triggers it; omitting limit entirely does not.
Common situations: Client UI letting users pick an unbounded 'load N messages' value; copy-pasting a cursor URL and hand-editing limit; a frontend sending limit as a float string after JSON serialization; automated scrapers probing with limit=1000.
Related errors
- invalid cursor
- runtime probe_result must be success or error
- failed runtime probes must not include counts
- successful runtime probes require all counts
- invalid runtime counts
AI-assisted analysis of multica-ai/multica@2c0912b6ec (2026-08-15).
Data as JSON: /api/errors/27b20e70d55d8c7d.
Report an issue: GitHub.