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

  1. Log the incoming projectId and fix the client/caller to send the real 24-hex-char ObjectId
  2. Generate a valid ObjectId for tests (e.g. new ObjectId().toString() or '507f1f77bcf86cd799439011')
  3. Check where the ID originates (link building, API response field) — send the correct field (project._id) not name/slug
  4. 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

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


AI-assisted analysis of overleaf/overleaf@28ad3b03b7 (2026-09-03). Data as JSON: /api/errors/ffe6aaa9e3ac40fd. Report an issue: GitHub.