nestjs/nest · error · InvalidJSONFormatException

Could not parse JSON: ${err.message} Request data: ${data}

Error message

Could not parse JSON: ${err.message}
Request data: ${data}

What it means

Thrown as InvalidJSONFormatException from TcpSocket.emitMessage() when JSON.parse(data) throws on the body of a parsed frame. By the time emitMessage runs, the length-prefixed framing has already succeeded and produced a complete string; this error means that string is not valid JSON. The message includes the underlying parse error and the raw request data for debugging. Like the other framing errors, the socket's 'error' event is emitted and the connection closed by onData().

Source

Thrown at packages/microservices/helpers/tcp-socket.ts:70

  ): any;

  private onData(data: Buffer) {
    try {
      this.handleData(data);
    } catch (e) {
      this.socket.emit(TcpEventsMap.ERROR, e.message);
      this.socket.end();
    }
  }

  protected abstract handleData(data: Buffer | string): any;

  protected emitMessage(data: string) {
    let message: Record<string, unknown>;
    try {
      message = JSON.parse(data);
    } catch (e) {
      throw new InvalidJSONFormatException(e, data);
    }
    message = message || {};
    this.socket.emit('message', message);
  }
}

View on GitHub (pinned to 6ec0e2783d)

Solutions

  1. Ensure the sender uses a serializer whose output the receiver's deserializer can parse — default both to JSON, or set both to the same custom serializer/deserializer pair.
  2. Validate payloads are JSON-serializable before sending (no BigInt without a custom serializer, no circular refs, no undefined).
  3. Check for encoding issues — the transport expects UTF-8 strings.
  4. If you need non-JSON, configure options.serializer and options.deserializer consistently on both ClientTCP and ServerTCP.

Example fix

// before
// sender: custom serializer emits a plain string
new ClientTCP({ ... , serializer: new PlainTextSerializer() });
// receiver: default JSON deserializer -> InvalidJSONFormatException

// after
// use matching serializer/deserializer on both sides
new ClientTCP({ ..., serializer: new MySerializer() });
new ServerTCP({ ..., deserializer: new MyDeserializer() });
Defensive patterns

Strategy: validation

Validate before calling

function assertJsonSerializable(payload: unknown) {
  try { JSON.stringify(payload); }
  catch (e) { throw new Error('Payload is not JSON-serializable: ' + e.message); }
}
assertJsonSerializable(payload);

Type guard

const isInvalidJsonFormat = (e: unknown): boolean =>
  /Could not parse JSON/.test((e as Error)?.message ?? '');

Try / catch

try {
  await firstValueFrom(client.send('x', payload));
} catch (e) {
  if (isInvalidJsonFormat(e)) {
    // align serializer (sender) with deserializer (receiver), or sanitize payload
  } else throw e;
}

Prevention

When it happens

Trigger: A well-framed TCP message whose body is not valid JSON (truncated payload, single quotes, trailing commas, comments, or accidental non-JSON text inside a valid length frame). A custom serializer that writes non-JSON (e.g. MessagePack, raw strings) while the receiver uses the default JSON deserializer. Encoding mismatches (UTF-16 vs UTF-8) producing unparseable characters.

Common situations: Mismatched serializer on the sender vs deserializer on the receiver (one side JSON, the other not). Hand-crafted frames where the JSON body is malformed. Encoding/locale issues on Windows or with binary blobs. A truncated write that happened to be exactly length-prefixed but contained a partial JSON document.

Related errors


AI-assisted analysis of nestjs/nest@6ec0e2783d (2026-08-03). Data as JSON: /data/errors/021cf14ab6a815ff.json. Report an issue: GitHub.