{"record":{"id":"b79ddc8cdb8a51ce","repo":"payloadcms/payload","slug":"cannot-finddistinct-by-a-virtual-field-that-isn-t","errorCode":null,"errorMessage":"Cannot findDistinct by a virtual field that isn't linked to a relationship field.","messagePattern":"Cannot findDistinct by a virtual field that isn't linked to a relationship field\\.","errorType":"http","errorClass":"APIError","httpStatus":500,"severity":"warning","filePath":"packages/payload/src/collections/operations/findDistinct.ts","lineNumber":156,"sourceCode":"      const hasAccess = await fieldResult.field.access.read({\n        collection: collectionConfig,\n        req,\n      })\n      if (!hasAccess) {\n        throw new Forbidden(req.t)\n      }\n    }\n\n    await validateSortQuery({\n      collectionConfig,\n      overrideAccess: overrideAccess!,\n      req,\n      sort: args.sort,\n    })\n\n    if ('virtual' in fieldResult.field && fieldResult.field.virtual) {\n      if (typeof fieldResult.field.virtual !== 'string') {\n        throw new APIError(\n          `Cannot findDistinct by a virtual field that isn't linked to a relationship field.`,\n        )\n      }\n\n      let relationPath: string = ''\n      let currentFields: FlattenedField[] = collectionConfig.flattenedFields\n      const fieldPathSegments = fieldResult.field.virtual.split('.')\n      for (const segment of fieldResult.field.virtual.split('.')) {\n        relationPath = `${relationPath}${segment}`\n        fieldPathSegments.shift()\n        const field = currentFields.find((e) => e.name === segment)!\n        if (\n          (field.type === 'relationship' || field.type === 'upload') &&\n          typeof field.relationTo === 'string'\n        ) {\n          break\n        }\n        if ('flattenedFields' in field) {","sourceCodeStart":138,"sourceCodeEnd":174,"githubUrl":"https://github.com/payloadcms/payload/blob/00c58b35c0ed348ddc22daabf467b139727214fd/packages/payload/src/collections/operations/findDistinct.ts#L138-L174","documentation":"In `findDistinctOperation`, if the resolved field is `virtual` (truthy) but `virtual` is not a string (i.e. `true` or a boolean), it throws `APIError`. Distinct on virtual fields only works when the virtual field declares a relationship path as a string; a bare boolean virtual has no backing relationship to deduplicate against.","triggerScenarios":"Calling findDistinct on a field configured with `virtual: true` (boolean) rather than `virtual: 'relation.subField'` (string path).","commonSituations":"Misconfigured virtual field; attempting distinct on a computed field with no relationship backing.","solutions":["Configure the virtual field with a string relationship path (`virtual: 'status.label'`), or","Choose a non-virtual field for the distinct query."],"exampleFix":"// before\n{ name: 'statusLabel', type: 'text', virtual: true }\n// after\n{ name: 'statusLabel', type: 'text', virtual: 'status.label' }","handlingStrategy":"validation","validationCode":"function isDistinctableVirtual(field) {\n  return !('virtual' in field) || !field.virtual || typeof field.virtual === 'string'\n}","typeGuard":"function isStringVirtual(field): boolean {\n  return typeof field?.virtual === 'string'\n}","tryCatchPattern":null,"preventionTips":["Do not run distinct on boolean-virtual fields.","Configure virtuals with relationship paths (`virtual: 'rel.sub'`) when distinct is needed."],"tags":["distinct","virtual-fields","config"],"backgroundTag":null,"analyzedSha":"00c58b35c0ed348ddc22daabf467b139727214fd","analyzedAt":"2026-08-12T20:45:03.758Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}