{"record":{"id":"d5c87c155508706b","repo":"toeverything/AFFiNE","slug":"query-too-long-d5c87c","errorCode":"query_too_long","errorMessage":"Query is too long, max length is ${max}.","messagePattern":"Query is too long, max length is (.+?)\\.","errorType":"exception","errorClass":"QueryTooLong","httpStatus":400,"severity":"warning","filePath":"packages/backend/server/src/models/workspace-analytics.ts","lineNumber":572,"sourceCode":"      generatedAt: now,\n    };\n  }\n\n  async adminPaginateAllSharedLinks(\n    options: AdminAllSharedLinksOptions\n  ): Promise<\n    OptionalTotalPaginated<AdminSharedLinkNode> & {\n      analyticsWindow: TimeWindowDto;\n    }\n  > {\n    const pagination: PaginationInput = {\n      ...options.pagination,\n      first: Math.min(Math.max(options.pagination.first ?? 10, 1), 100),\n      offset: Math.max(options.pagination.offset ?? 0, 0),\n    };\n    const keyword = options.keyword?.trim();\n    if (keyword && keyword.length > DOC_MEMBER_QUERY_MAX_LENGTH) {\n      throw new QueryTooLong({ max: DOC_MEMBER_QUERY_MAX_LENGTH });\n    }\n\n    const includeTotal = options.includeTotal ?? false;\n    const orderBy = options.orderBy ?? 'UpdatedAtDesc';\n    const analyticsWindowDays = clampInt(\n      options.analyticsWindowDays,\n      1,\n      90,\n      DEFAULT_ANALYTICS_WINDOW_DAYS\n    );\n    const now = new Date();\n    const currentDay = startOfUtcDay(now);\n    const analyticsFrom = addUtcDays(currentDay, -(analyticsWindowDays - 1));\n\n    const cursor = parseJsonCursor<SharedLinkCursor>(pagination.after ?? null);\n    const cursorCondition = this.buildSharedLinkCursorCondition(\n      orderBy,\n      cursor","sourceCodeStart":554,"sourceCodeEnd":590,"githubUrl":"https://github.com/toeverything/AFFiNE/blob/26c515e050211269e911f7d9cfe162a26c83ed98/packages/backend/server/src/models/workspace-analytics.ts#L554-L590","documentation":"Thrown by the admin shared-links analytics list (workspace-analytics.ts:572) when the search keyword exceeds DOC_MEMBER_QUERY_MAX_LENGTH (255). The check runs after trimming and protects the downstream ILIKE query from pathological inputs. UserFriendlyError QueryTooLong, code query_too_long, type invalid_input, HTTP 400, data {max:255}.","triggerScenarios":"GET on the admin analytics shared-links endpoint with ?keyword longer than 255 characters.","commonSituations":"User pastes a large blob into the search box; an automated client omits a length clamp; adversarial/long input sent to probe limits.","solutions":["Trim and shorten the keyword to <=255 characters before sending.","Validate the length client-side and disable submit when exceeded.","If a broader search is needed, use a dedicated filter/export endpoint instead of the keyword param."],"exampleFix":"// before\nconst keyword = rawInput;\n// after\nconst keyword = rawInput.trim().slice(0, 255);","handlingStrategy":"validation","validationCode":"const DOC_MEMBER_QUERY_MAX_LENGTH = 255;\nfunction safeKeyword(input: string): string {\n  return input.trim().slice(0, DOC_MEMBER_QUERY_MAX_LENGTH);\n}","typeGuard":null,"tryCatchPattern":"import { QueryTooLong } from '../base/error/errors.gen';\n\ntry {\n  await models.workspaceAnalytics.adminListSharedLinks({ keyword, ... });\n} catch (e) {\n  if (e instanceof QueryTooLong) {\n    // shorten the keyword and retry\n  } else throw e;\n}","preventionTips":["Clamp search keywords to 255 characters client-side before submit.","Disable the submit button when the query exceeds the limit.","Use a dedicated filter/export endpoint for very broad queries."],"tags":["analytics","input-validation","search"],"backgroundTag":null,"analyzedSha":"26c515e050211269e911f7d9cfe162a26c83ed98","analyzedAt":"2026-08-12T13:15:16.447Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}