nestjs/nest · error
CONN_ERR
CONN_ERR
Error message
CONN_ERR
What it means
NestJS microservices error surfaced by DisconnectedClientController (integration/microservices/src/disconnected.controller.ts). ClientProxyFactory.create(options) builds a transport client (TCP/Redis/RabbitMQ/NATS/MQTT) from request-body options, then client.send({cmd:'none'}, [1,2,3]) emits a message. When the transport cannot reach its broker/service, NestJS's ClientProxy emits an error whose code is CONN_ERR (its own 'connection not available' code) or one of ECONNREFUSED/ENOTFOUND/CONNECTION_REFUSED. The catchError at line 22-33 destructures `error?.err ?? error ?? { code: 'CONN_ERR' }` and normalises connection-class codes into RequestTimeoutException('ECONNREFUSED'); the bare `{ code: 'CONN_ERR' }` fallback covers errors with no structured code. This controller exists specifically to demonstrate that disconnection path.
Source
Thrown at integration/microservices/src/disconnected.controller.ts:23
Post,
RequestTimeoutException,
} from '@nestjs/common';
import { ClientProxyFactory } from '@nestjs/microservices';
import { Observable, throwError } from 'rxjs';
import { catchError, tap } from 'rxjs/operators';
@Controller()
export class DisconnectedClientController {
@Post()
call(@Body() options): Observable<number> {
const client = ClientProxyFactory.create(options);
return client.send<number, number[]>({ cmd: 'none' }, [1, 2, 3]).pipe(
// tap(
// console.log.bind(console, 'data'),
// console.error.bind(console, 'error'),
// ),
catchError(error => {
const { code } = error?.err ?? error ?? { code: 'CONN_ERR' };
return throwError(() =>
code === 'ECONNREFUSED' ||
code === 'CONN_ERR' ||
code === 'ENOTFOUND' ||
code === 'CONNECTION_REFUSED' ||
error.message.includes('Connection is closed.')
? new RequestTimeoutException('ECONNREFUSED')
: new InternalServerErrorException(),
);
}),
tap({
error: () => client.close(),
}),
);
}
}
View on GitHub (pinned to 6ec0e2783d)
Solutions
- Start the transport the options point at (e.g., docker run redis, or the partner microservice) and re-issue the request.
- Verify host/port in the request body actually have a listener before sending.
- Call client.connect() (or rely on NestJS eager connect) and await it so connection failures surface before the first send rather than as CONN_ERR mid-stream.
- Do not accept raw transport options from the request body in production — validate/whitelist them, or build the client from trusted config.
Example fix
// before
const client = ClientProxyFactory.create(options);
return client.send<number, number[]>({ cmd: 'none' }, [1, 2, 3]).pipe(...)
// after
if (!options || !options.transport) {
throw new BadRequestException('transport options required');
}
const client = ClientProxyFactory.create(options);
await client.connect(); // surface connection failure explicitly
return client.send<number, number[]>({ cmd: 'none' }, [1, 2, 3]).pipe(...) Defensive patterns
Strategy: try-catch
Validate before calling
// Validate transport options before creating the client
const ALLOWED_TRANSPORTS = new Set(['TCP', 'REDIS', 'RMQ', 'NATS', 'MQTT', 'KAFKA']);
function isValidTransportOptions(v: unknown): v is { transport: string; options: Record<string, unknown> } {
if (typeof v !== 'object' || v === null) return false;
const t = (v as any).transport;
return typeof t === 'string' && ALLOWED_TRANSPORTS.has(t)
&& typeof (v as any).options === 'object';
}
// Optionally probe reachability before sending
import { createConnection } from 'node:net';
async function canReach(host: string, port: number, ms = 1000) {
return new Promise<boolean>(resolve => {
const s = createConnection({ host, port }, () => { s.destroy(); resolve(true); });
s.setTimeout(ms, () => { s.destroy(); resolve(false); });
s.on('error', () => resolve(false));
});
} Type guard
function isConnectionError(e: unknown): boolean {
const code = (e as any)?.err?.code ?? (e as any)?.code ?? (e as NodeJS.ErrnoException)?.code;
return ['CONN_ERR', 'ECONNREFUSED', 'ENOTFOUND', 'CONNECTION_REFUSED', 'ECONNRESET'].includes(code);
} Try / catch
client.send<number, number[]>({ cmd: 'none' }, [1, 2, 3]).pipe(
catchError(error => {
const code = error?.err?.code ?? error?.code ?? 'CONN_ERR';
if (['CONN_ERR', 'ECONNREFUSED', 'ENOTFOUND', 'CONNECTION_REFUSED'].includes(code)) {
return throwError(() => new RequestTimeoutException('broker unreachable'));
}
return throwError(() => new InternalServerErrorException(error?.message));
}),
tap({ error: () => client.close() }),
) Prevention
- Start the broker/service the transport points at before issuing requests.
- Await client.connect() so connection failures surface before the first send.
- Never accept raw transport options from the request body in production — whitelist them.
- Centralise the connection-error normalisation (the codes listed in catchError) into one filter/operator.
When it happens
Trigger: POST to the controller with transport options pointing at a broker/service that isn't running — e.g., body { transport: 'REDIS', options: { host: 'localhost', port: 6379 } } with no Redis up, or a TCP microservice on a dead port. The first emitted message hits a closed/unreachable socket and the stream errors with code CONN_ERR.
Common situations: Broker (Redis/RabbitMQ/NATS/MQTT) never started locally; wrong host/port in options; service registry/DNS resolves but nothing listens on that port; firewall/network policy blocks the port; the receiving microservice crashed between connection setup and the send; accepting arbitrary options from the request body (as this controller does) lets clients target unreachable hosts.
Related errors
- 3
- The "connect()" method is not supported in gRPC mode.
- Method is not supported in gRPC mode. Use ClientGrpc instead
- Method is not supported in gRPC mode.
- No consumer initialized. Please, call the "connect" method f
AI-assisted analysis of nestjs/nest@6ec0e2783d (2026-08-03).
Data as JSON: /data/errors/8989a89e81468368.json.
Report an issue: GitHub.