{"record":{"id":"1f50808283c84c18","repo":"RocketChat/Rocket.Chat","slug":"invalid-params","errorCode":"invalid-params","errorMessage":"validatorFunc.errors?.map((error: any) => error.message).join('\\n ')","messagePattern":"validatorFunc\\.errors\\?\\.map\\(\\(error: any\\) => error\\.message\\)\\.join\\('\\\\n '\\)","errorType":"validation","errorClass":"Meteor.Error","httpStatus":400,"severity":"error","filePath":"apps/meteor/server/api/ApiClass.ts","lineNumber":905,"sourceCode":"\t\t\t\t\t\tlet result;\n\n\t\t\t\t\t\tconst connection = { ...generateConnection(this.requestIp, this.request.headers), token: this.token };\n\t\t\t\t\t\tthis.connection = connection;\n\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\tif (options.deprecation) {\n\t\t\t\t\t\t\t\tparseDeprecation(this, options.deprecation);\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tawait api.enforceRateLimit(objectForRateLimitMatch, this.request, this.response, this.userId);\n\n\t\t\t\t\t\t\tif (_options.validateParams) {\n\t\t\t\t\t\t\t\tconst requestMethod = this.request.method as Method;\n\t\t\t\t\t\t\t\tconst validatorFunc =\n\t\t\t\t\t\t\t\t\ttypeof _options.validateParams === 'function' ? _options.validateParams : _options.validateParams[requestMethod];\n\n\t\t\t\t\t\t\t\tif (validatorFunc && !validatorFunc(requestMethod === 'GET' ? this.queryParams : this.bodyParams)) {\n\t\t\t\t\t\t\t\t\tthrow new Meteor.Error('invalid-params', validatorFunc.errors?.map((error: any) => error.message).join('\\n '));\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tif (\n\t\t\t\t\t\t\t\tthis.userId &&\n\t\t\t\t\t\t\t\t(await api.processTwoFactor({\n\t\t\t\t\t\t\t\t\tuserId: this.userId,\n\t\t\t\t\t\t\t\t\trequest: this.request,\n\t\t\t\t\t\t\t\t\toptions: _options,\n\t\t\t\t\t\t\t\t\tconnection: connection as unknown as IMethodConnection,\n\t\t\t\t\t\t\t\t}))\n\t\t\t\t\t\t\t) {\n\t\t\t\t\t\t\t\tthis.twoFactorChecked = true;\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tthis.parseJsonQuery = () => api.parseJsonQuery(this);\n\n\t\t\t\t\t\t\tif (options.applyMeteorContext) {\n\t\t\t\t\t\t\t\tconst invocation = APIClass.createMeteorInvocation(connection, this.userId, this.token);","sourceCodeStart":887,"sourceCodeEnd":923,"githubUrl":"https://github.com/RocketChat/Rocket.Chat/blob/b2c16d5842cbe6b69b59bdf6fc5e5f1afcd1f0b0/apps/meteor/server/api/ApiClass.ts#L887-L923","documentation":"The validated REST layer (API.v1.get/post/... in ApiClass) runs each route's ajv validator — validateParams as a function or a per-HTTP-method map — over queryParams for GET and bodyParams for other methods. When validation fails it throws invalid-params with all ajv error messages joined by newlines, so the message enumerates exactly which properties failed which keywords.","triggerScenarios":"Sending a REST request whose body or query fails the route's ajv schema: missing required properties, wrong types (e.g. count as string '50'), or extra properties when the schema sets additionalProperties: false.","commonSituations":"Client library older than the server's @rocket.chat/rest-typings schemas, integrations sending stringified numbers/booleans, renamed or deprecated fields, wrong payload casing.","solutions":["Read the joined ajv messages in the error text — they name the failing property and keyword (required, type, additionalProperties, etc.).","Compare the payload against the route's schema in @rocket.chat/rest-typings (or the REST API docs) and fix mismatches.","Send native JSON types (numbers as numbers), drop unknown fields, and include all required ones.","After a server upgrade, re-test integrations — schema changes surface here."],"exampleFix":"// before — misspelled field, string count\napi.post('/v1/users.create', { username: 'a', email: 'a@b.c', passwrd: 'x', count: '5' });\n\n// after\napi.post('/v1/users.create', { username: 'a', email: 'a@b.c', password: 'x' });","handlingStrategy":"validation","validationCode":"// client-side pre-validation against the same ajv schema the server uses\nimport Ajv from 'ajv';\nconst validate = new Ajv({ allErrors: true }).compile(schemaForRoute); // from @rocket.chat/rest-typings\nif (!validate(payload)) {\n\tthrow new Error(validate.errors?.map((e) => e.message).join('\\n'));\n}","typeGuard":"const isShape = <T>(validate: (x: unknown) => boolean, payload: unknown): payload is T => validate(payload);","tryCatchPattern":"try {\n\tawait api.post('/v1/users.create', payload);\n} catch (e: any) {\n\tif (e?.error === 'invalid-params') {\n\t\t// e.message lists each failing ajv keyword — fix the named fields and retry\n\t}\n\tthrow e;\n}","preventionTips":["Generate/derive clients from the server's REST typings so payloads always match current schemas","Send native JSON types — numbers and booleans, not strings","Run contract tests against schemas after server upgrades"],"tags":["rest-api","ajv","validation","schema"],"backgroundTag":"schema-validation-failed","analyzedSha":"b2c16d5842cbe6b69b59bdf6fc5e5f1afcd1f0b0","analyzedAt":"2026-08-18T15:26:39.429Z","schemaVersion":2},"datasetVersion":"2026-08-21T13:17:26.733Z"}