{"record":{"id":"f64b7b15a8035448","repo":"RocketChat/Rocket.Chat","slug":"error-invalid-field","errorCode":"error-invalid-field","errorMessage":"bio","messagePattern":"bio","errorType":"exception","errorClass":"Meteor.Error","httpStatus":null,"severity":"error","filePath":"apps/meteor/server/meteor-methods/users/saveUserProfile.ts","lineNumber":91,"sourceCode":"\t\t\t!(await saveUserIdentity({\n\t\t\t\t_id: this.userId,\n\t\t\t\tname: settings.realname,\n\t\t\t\tusername: settings.username,\n\t\t\t}))\n\t\t) {\n\t\t\tthrow new Meteor.Error('error-could-not-save-identity', 'Could not save user identity', {\n\t\t\t\tmethod: 'saveUserProfile',\n\t\t\t});\n\t\t}\n\t}\n\n\tif (settings.statusType || settings.statusText != null) {\n\t\tawait setUserStatusMethod(user, settings.statusType as UserStatus, settings.statusText);\n\t}\n\n\tif (user && (settings.bio || settings.bio === '')) {\n\t\tif (typeof settings.bio !== 'string') {\n\t\t\tthrow new Meteor.Error('error-invalid-field', 'bio', {\n\t\t\t\tmethod: 'saveUserProfile',\n\t\t\t});\n\t\t}\n\t\tif (settings.bio.length > MAX_BIO_LENGTH) {\n\t\t\tthrow new Meteor.Error('error-bio-size-exceeded', `Bio size exceeds ${MAX_BIO_LENGTH} characters`, {\n\t\t\t\tmethod: 'saveUserProfile',\n\t\t\t});\n\t\t}\n\t\tawait Users.setBio(user._id, settings.bio.trim());\n\t}\n\n\tif (user && (settings.nickname || settings.nickname === '')) {\n\t\tif (typeof settings.nickname !== 'string') {\n\t\t\tthrow new Meteor.Error('error-invalid-field', 'nickname', {\n\t\t\t\tmethod: 'saveUserProfile',\n\t\t\t});\n\t\t}\n\t\tif (settings.nickname.length > MAX_NICKNAME_LENGTH) {","sourceCodeStart":73,"sourceCodeEnd":109,"githubUrl":"https://github.com/RocketChat/Rocket.Chat/blob/b2c16d5842cbe6b69b59bdf6fc5e5f1afcd1f0b0/apps/meteor/server/meteor-methods/users/saveUserProfile.ts#L73-L109","documentation":"A runtime type guard on the bio field: saveUserProfile rejects settings.bio when it is present (truthy or empty string) but not a JS string (typeof settings.bio !== 'string'). No database write happens; the check runs before the length check and Users.setBio.","triggerScenarios":"Calling saveUserProfile with bio as a number, object, or array - e.g. bio: 123, bio: { text: '...' } - typically from a custom client, integration, or a form binding that did not cast the input value.","commonSituations":"Number-input form fields bound without String(); bots/integrations posting untyped JSON; REST-to-DDP bridges that pass raw JSON values through.","solutions":["Cast and validate on the client before calling: ensure typeof bio === 'string'","Type the settings payload (bio?: string) in TS clients so the compiler blocks non-string values","Inspect the actual DDP wire payload if a stock client triggers it - some serializer upstream is corrupting the value"],"exampleFix":"// before\nMeteor.call('saveUserProfile', { bio: bioInput.valueAsNumber }, customFields);\n\n// after\nMeteor.call('saveUserProfile', { bio: String(bioInput.value) }, customFields);","handlingStrategy":"type-guard","validationCode":"if ('bio' in settings && typeof settings.bio !== 'string') {\n  throw new TypeError('bio must be a string');\n}","typeGuard":"const isOptionalString = (v: unknown): v is string | undefined => v === undefined || typeof v === 'string';","tryCatchPattern":"catch (err) {\n  if (err instanceof Meteor.Error && err.error === 'error-invalid-field' && err.reason === 'bio') {\n    showFieldError('bio', 'Bio must be text');\n  }\n}","preventionTips":["Type the settings payload (bio?: string) in TS clients","Cast form inputs with String() at the boundary instead of trusting bound types","Add contract tests that send malformed field types and assert client-side rejection"],"tags":["meteor","validation","profile","typescript"],"backgroundTag":"invalid-field-type","analyzedSha":"b2c16d5842cbe6b69b59bdf6fc5e5f1afcd1f0b0","analyzedAt":"2026-08-18T15:26:39.429Z","schemaVersion":2},"datasetVersion":"2026-08-21T23:17:16.201Z"}