{"record":{"id":"e60f090782218f36","repo":"usememos/memos","slug":"invalidargument-e60f09","errorCode":"InvalidArgument","errorMessage":"empty order_by","messagePattern":"empty order_by","errorType":"validation","errorClass":null,"httpStatus":400,"severity":"error","filePath":"server/router/api/v1/memo_service_query.go","lineNumber":13,"sourceCode":"package v1\n\nimport (\n\t\"strings\"\n\n\t\"github.com/pkg/errors\"\n\n\t\"github.com/usememos/memos/store\"\n)\n\nfunc (*APIV1Service) parseMemoOrderBy(orderBy string, memoFind *store.FindMemo) error {\n\tif strings.TrimSpace(orderBy) == \"\" {\n\t\treturn errors.New(\"empty order_by\")\n\t}\n\n\t// Split by comma to support multiple sort fields per AIP-132.\n\tfields := strings.Split(orderBy, \",\")\n\n\t// Track if we've seen pinned field.\n\thasPinned := false\n\thasExplicitTimeField := false\n\n\tfor _, field := range fields {\n\t\tparts := strings.Fields(strings.TrimSpace(field))\n\t\tif len(parts) == 0 {\n\t\t\tcontinue\n\t\t}\n\n\t\tfieldName := parts[0]\n\t\tfieldDirection := \"desc\" // default per AIP-132 (we use desc as default for time fields)\n\t\tif len(parts) > 1 {","sourceCodeStart":1,"sourceCodeEnd":31,"githubUrl":"https://github.com/usememos/memos/blob/14d757ce1fb31c78590f374bc042f8dbedbc20d7/server/router/api/v1/memo_service_query.go#L1-L31","documentation":"parseMemoOrderBy implements AIP-132 style ordering for ListMemos: it splits the order_by string on commas and parses each field with optional ASC/DESC direction. An order_by that is empty or only whitespace is rejected up front as InvalidArgument, because there is no field to sort by.","triggerScenarios":"ListMemos(request.order_by = ''), order_by = '   ', a UI sort control reset to blank but still serialized into the request, or a client defaulting the field to an empty string.","commonSituations":"Frontend state where 'sort by' is optional and empty string leaks into the RPC; scripts copying request templates and blanking sort; upgrades that changed order_by from optional to validated.","solutions":["Omit order_by entirely when the user has not chosen a sort (server default applies), or send a valid field like 'display_ts DESC'.","Guard in the client: if (!orderBy.trim()) delete request.orderBy.","Check supported field names/directions in memo_service_query.go if a non-empty value is also rejected downstream."],"exampleFix":"// before\nconst resp = await memoClient.listMemos({ orderBy: sortBy }); // sortBy = ''\n\n// after\nconst req = { pageSize: 50 };\nif (sortBy.trim()) req.orderBy = sortBy; // e.g. 'display_ts DESC'\nconst resp = await memoClient.listMemos(req);","handlingStrategy":"validation","validationCode":"if (orderBy !== undefined && !orderBy.trim()) {\n  throw new Error('order_by must be non-empty when provided');\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Omit order_by when no explicit sort is chosen rather than sending ''.","Centralize request building so optional fields are deleted when blank.","Follow AIP-132 syntax: 'field ASC|DESC', comma-separated for multiple fields."],"tags":["validation","list-memos","order-by","aip-132","invalid-argument"],"backgroundTag":null,"analyzedSha":"14d757ce1fb31c78590f374bc042f8dbedbc20d7","analyzedAt":"2026-08-15T09:27:36.538Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}