RocketChat/Rocket.Chat · warning · ContactNotFoundError
error-contact-not-found
Error message
error-contact-not-found
What it means
In the Outbound Message wizard's RecipientForm, the contact is fetched via useQuery on omnichannelQueryKeys.contact(contactId). The queryFn calls getContact({ contactId }) and throws ContactNotFoundError (message 'error-contact-not-found', a FormFetchError subclass) when the returned contact is marked unknown — a stopgap until the endpoint itself handles unknown contacts. It puts the query in an error state so the form can validate the contact field.
Source
Thrown at apps/meteor/client/views/omnichannel/components/outboundMessage/components/OutboundMessageWizard/forms/RecipientForm/RecipientForm.tsx:85
const getContact = useEndpoint('GET', '/v1/omnichannel/contacts.get');
const getProvider = useEndpoint('GET', '/v1/omnichannel/outbound/providers/:id/metadata', { id: providerId });
const customActions = useMemo(() => renderActions?.({ isSubmitting }), [isSubmitting, renderActions]);
const {
data: contact,
isError: isErrorContact,
isSuccess: isSuccessContact,
isFetching: isFetchingContact,
refetch: refetchContact,
} = useQuery({
queryKey: omnichannelQueryKeys.contact(contactId),
queryFn: async () => {
const data = await getContact({ contactId });
// TODO: Can be safely removed once unknown contacts handling is added to the endpoint
if (data?.contact && data.contact.unknown) {
throw new ContactNotFoundError();
}
return data;
},
staleTime: 5 * 60 * 1000,
select: (data) => data?.contact || undefined,
enabled: !!contactId,
});
const {
data: provider,
isError: isErrorProvider,
isSuccess: isSuccessProvider,
isFetching: isFetchingProvider,
refetch: refetchProvider,
} = useQuery({
queryKey: omnichannelQueryKeys.outboundProviderMetadata(providerId),
queryFn: () => getProvider(),View on GitHub (pinned to b2c16d5842)
Solutions
- Convert the unknown visitor into a registered contact first (Contacts UI or POST /omnichannel/contact), then reopen the wizard.
- If the contact was deleted or merged, re-select the recipient to obtain a fresh contactId.
- Code-level: key the form off isErrorContact to prompt contact creation instead of submitting.
Example fix
// before
if (data?.contact && data.contact.unknown) {
throw new ContactNotFoundError();
}
// caller-side: block step advance while contact query is in error
if (isErrorContact) {
validateContactField(true); // show field error, do not proceed
return;
} Defensive patterns
Strategy: validation
Validate before calling
const { contact } = await getContact({ contactId });
if (!contact || contact.unknown) {
// convert/register the contact before opening the outbound wizard
} Type guard
const isUsableContact = (c: IContact | undefined): c is IContact => Boolean(c && !c.unknown && typeof c._id === 'string');
Prevention
- Convert unknown visitors to contacts before outbound messaging.
- Gate wizard entry on a resolved, non-unknown contact.
- Handle isErrorContact by prompting re-selection.
When it happens
Trigger: Opening the outbound-message wizard with a contactId whose contact record has unknown: true (visitor not yet a registered contact), or a contactId that resolves to no usable contact object.
Common situations: Starting an outbound conversation from a visitor/lead that never became a full contact; stale contactId passed from a previous session; records created by integrations with unknown flag set.
Related errors
- error-provider-not-found
- error-department-not-found
- error-agent-not-found
- error-invalid-contact
- error-invalid-agent
AI-assisted analysis of RocketChat/Rocket.Chat@b2c16d5842 (2026-08-18).
Data as JSON: /api/errors/62554309a7a95854.
Report an issue: GitHub.