hcengineering/platform · error · PlatformError

No project type found

Error message

No project type found

What it means

updateProjectType first loads the existing ProjectType by id via client.findOne; if it is missing the code throws a PlatformError wrapping unknownStatus('No project type found'). This is a deliberate not-found signal (not a crash), meaning the caller passed a projectType Ref that doesn't exist in the database.

Source

Thrown at plugins/task/src/utils.ts:262

  // TODO: not needed ???
  await client.createMixin(targetProjectClassId, core.class.Mixin, core.space.Model, task.mixin.ProjectTypeClass, {
    projectType: _id
  })

  return tmpl
}

/**
 * @public
 */
export async function updateProjectType (
  client: TxOperations,
  projectType: Ref<ProjectType>,
  tasks: TaskTypeWithFactory[]
): Promise<void> {
  const current = await client.findOne(task.class.ProjectType, { _id: projectType })
  if (current === undefined) {
    throw new PlatformError(unknownStatus('No project type found'))
  }

  const _tasks: Ref<TaskType>[] = [...current.tasks]
  const tasksData = new Map<Ref<TaskType>, Data<TaskType>>()
  const _statues = new Set<Ref<Status>>()

  const hasUpdates = await createTaskTypes(tasks, projectType, client, _statues, tasksData, _tasks, true)

  if (hasUpdates) {
    const ttypes = await client.findAll<TaskType>(task.class.TaskType, { _id: { $in: _tasks } })
    const newStatuses = calculateStatuses(
      {
        statuses: current.statuses,
        tasks: _tasks
      },
      new Map(ttypes.map((it) => [it._id, it])),
      []
    )

View on GitHub (pinned to 63e28dc964)

Solutions

  1. Re-fetch the project type (client.findOne(task.class.ProjectType, { _id })) and handle undefined before updating
  2. Verify the Ref comes from the same workspace/connection you're updating against
  3. If deletion is concurrent, catch the PlatformError and inform the user the type no longer exists
  4. Check for id typos by listing existing ProjectTypes and matching by name

Example fix

// before
await updateProjectType(client, maybeDeletedId, tasks) // throws if gone
// after
const pt = await client.findOne(task.class.ProjectType, { _id: maybeDeletedId })
if (pt === undefined) {
  console.warn('Project type no longer exists, skipping update')
  return
}
await updateProjectType(client, pt._id, tasks)
Defensive patterns

Strategy: validation

Validate before calling

const current = await client.findOne(task.class.ProjectType, { _id: projectType })
if (current === undefined) {
  // skip or recreate; do not call updateProjectType
  return
}
await updateProjectType(client, projectType, tasks)

Type guard

async function projectTypeExists (client: TxOperations, id: Ref<ProjectType>): Promise<boolean> {
  return (await client.findOne(task.class.ProjectType, { _id: id })) !== undefined
}

Try / catch

try {
  await updateProjectType(client, projectType, tasks)
} catch (err) {
  if (err instanceof PlatformError && err.message.includes('No project type found')) {
    console.warn('Project type was deleted; skipping update', projectType)
    return
  }
  throw err
}

Prevention

When it happens

Trigger: Calling updateProjectType with a stale or deleted Ref<ProjectType>; passing an id from another workspace/db; a race where the project type was deleted between listing and updating.

Common situations: UI holding an outdated project type after concurrent deletion; hardcoded ids in scripts/tests; cross-tenant data mixing.

Understand the failure class

Background: "Not found" and "does not exist" errors: why "Task not found", "No such folder", and "Can't find" fire when a lookup comes back empty — this error's family across 14 libraries.

Related errors


AI-assisted analysis of hcengineering/platform@63e28dc964 (2026-08-29). Data as JSON: /api/errors/d78d0ddd104753c5. Report an issue: GitHub.