{"record":{"id":"ffe6aaa9e3ac40fd","repo":"overleaf/overleaf","slug":"invalid-projectid","errorCode":null,"errorMessage":"Invalid projectId","messagePattern":"Invalid projectId","errorType":"http","errorClass":null,"httpStatus":400,"severity":"warning","filePath":"services/chat/app/js/Features/Messages/MessageHttpController.js","lineNumber":17,"sourceCode":"import logger from '@overleaf/logger'\nimport * as MessageManager from './MessageManager.js'\nimport * as MessageFormatter from './MessageFormatter.js'\nimport * as ThreadManager from '../Threads/ThreadManager.js'\nimport { ObjectId } from '../../mongodb.js'\nimport { promiseMapWithLimit } from '@overleaf/promise-utils'\n\nconst DEFAULT_MESSAGE_LIMIT = 50\nconst MAX_MESSAGE_LENGTH = 10 * 1024 // 10kb, about 1,500 words\n\nfunction readContext(context, req) {\n  req.body = context.requestBody\n  req.params = context.params.path\n  req.query = context.params.query\n  if (typeof req.params.projectId !== 'undefined') {\n    if (!ObjectId.isValid(req.params.projectId)) {\n      context.res.status(400).setBody('Invalid projectId')\n    }\n  }\n  if (typeof req.params.threadId !== 'undefined') {\n    if (!ObjectId.isValid(req.params.threadId)) {\n      context.res.status(400).setBody('Invalid threadId')\n    }\n  }\n}\n\n/**\n * @param context\n * @param {(req: unknown, res: unknown) => Promise<unknown>} ControllerMethod\n * @returns {Promise<*>}\n */\nexport async function callMessageHttpController(context, ControllerMethod) {\n  const req = {}\n  readContext(context, req)\n  if (context.res.statusCode !== 400) {","sourceCodeStart":1,"sourceCodeEnd":35,"githubUrl":"https://github.com/overleaf/overleaf/blob/28ad3b03b71cb4311decdcb55c36b33ec10d72db/services/chat/app/js/Features/Messages/MessageHttpController.js#L1-L35","documentation":"In services/chat's MessageHttpController, readContext validates path parameters from the OpenAPI/exegesis request context before handlers run. If the request path includes a projectId that is not a valid MongoDB ObjectId (per ObjectId.isValid), it short-circuits with HTTP 400 and the body 'Invalid projectId' instead of invoking the handler.","triggerScenarios":"Any chat HTTP route whose path contains :projectId (e.g. GET /project/:projectId/messages) called with a malformed value: empty-ish, too short, containing illegal hex characters, or a 24-char string that still fails ObjectId validation.","commonSituations":"Client code passing a project 'slug' or numeric ID instead of a Mongo ObjectId; truncated IDs from string slicing; URL-encoded or whitespace-padded values; tests constructing fake IDs like 'project-1'.","solutions":["Log the incoming projectId and fix the client/caller to send the real 24-hex-char ObjectId","Generate a valid ObjectId for tests (e.g. new ObjectId().toString() or '507f1f77bcf86cd799439011')","Check where the ID originates (link building, API response field) — send the correct field (project._id) not name/slug","If the handler should accept non-ObjectId identifiers, change the route/controller validation instead of the caller"],"exampleFix":"// before\ncurl /project/abc123/messages          // 400 Invalid projectId\n// after — send a valid 24-hex ObjectId\ncurl /project/507f1f77bcf86cd799439011/messages","handlingStrategy":"validation","validationCode":"const PROJECT_ID_RE = /^[0-9a-fA-F]{24}$/\nif (typeof projectId !== 'string' || !PROJECT_ID_RE.test(projectId)) {\n  throw new Error(`Invalid projectId: ${projectId}`)\n}","typeGuard":"function isValidProjectId(v) {\n  return typeof v === 'string' && /^[0-9a-fA-F]{24}$/.test(v)\n}","tryCatchPattern":"try {\n  const res = await fetch(`/project/${projectId}/messages`)\n  if (res.status === 400) {\n    const body = await res.text()\n    if (body === 'Invalid projectId') {\n      console.error('projectId is not a valid ObjectId:', projectId)\n    }\n  }\n} catch (e) {\n  console.error('request failed', e)\n}","preventionTips":["Always send the Mongo _id field, never slugs or numeric keys","Validate ObjectIds on the client before issuing requests","Generate test fixtures with new ObjectId().toString()","Beware truncation when building URLs from string slicing"],"tags":["validation","mongodb","objectid","http-400","chat"],"backgroundTag":"invalid-objectid","analyzedSha":"28ad3b03b71cb4311decdcb55c36b33ec10d72db","analyzedAt":"2026-09-03T02:10:22.807Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-10T07:17:11.731Z"}