overleaf/overleaf · warning
Invalid projectId
Error message
Invalid projectId
What it means
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.
Source
Thrown at services/chat/app/js/Features/Messages/MessageHttpController.js:17
import logger from '@overleaf/logger'
import * as MessageManager from './MessageManager.js'
import * as MessageFormatter from './MessageFormatter.js'
import * as ThreadManager from '../Threads/ThreadManager.js'
import { ObjectId } from '../../mongodb.js'
import { promiseMapWithLimit } from '@overleaf/promise-utils'
const DEFAULT_MESSAGE_LIMIT = 50
const MAX_MESSAGE_LENGTH = 10 * 1024 // 10kb, about 1,500 words
function readContext(context, req) {
req.body = context.requestBody
req.params = context.params.path
req.query = context.params.query
if (typeof req.params.projectId !== 'undefined') {
if (!ObjectId.isValid(req.params.projectId)) {
context.res.status(400).setBody('Invalid projectId')
}
}
if (typeof req.params.threadId !== 'undefined') {
if (!ObjectId.isValid(req.params.threadId)) {
context.res.status(400).setBody('Invalid threadId')
}
}
}
/**
* @param context
* @param {(req: unknown, res: unknown) => Promise<unknown>} ControllerMethod
* @returns {Promise<*>}
*/
export async function callMessageHttpController(context, ControllerMethod) {
const req = {}
readContext(context, req)
if (context.res.statusCode !== 400) {View on GitHub (pinned to 28ad3b03b7)
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
Example fix
// before curl /project/abc123/messages // 400 Invalid projectId // after — send a valid 24-hex ObjectId curl /project/507f1f77bcf86cd799439011/messages
Defensive patterns
Strategy: validation
Validate before calling
const PROJECT_ID_RE = /^[0-9a-fA-F]{24}$/
if (typeof projectId !== 'string' || !PROJECT_ID_RE.test(projectId)) {
throw new Error(`Invalid projectId: ${projectId}`)
} Type guard
function isValidProjectId(v) {
return typeof v === 'string' && /^[0-9a-fA-F]{24}$/.test(v)
} Try / catch
try {
const res = await fetch(`/project/${projectId}/messages`)
if (res.status === 400) {
const body = await res.text()
if (body === 'Invalid projectId') {
console.error('projectId is not a valid ObjectId:', projectId)
}
}
} catch (e) {
console.error('request failed', e)
} Prevention
- 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
When it happens
Trigger: 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.
Common situations: 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'.
Related errors
- Invalid threadId
- Invalid userId
- invalid project id
- user ID not valid: ${userId}
- invalid --user-id: ${userIdArg}
AI-assisted analysis of overleaf/overleaf@28ad3b03b7 (2026-09-03).
Data as JSON: /api/errors/ffe6aaa9e3ac40fd.
Report an issue: GitHub.