Skip to content

node:https: ERR_TLS_CERT_ALTNAME_INVALID when manual Host header contains a port #26333

@tomislavcivcija

Description

@tomislavcivcija

What version of Bun is running?

1.3.6+d530ed993

What platform is your computer?

Linux 6.12.57+deb13-cloud-amd64 (Debian 14.2.0-19) x86_64

Reproduction in comment bellow:

#26333 (comment)


Summary

When running under Bun 1.3.6, the MinIO JS client (minio@8.0.6) fails with ERR_TLS_CERT_ALTNAME_INVALID during putObject() uploads over HTTPS, even though:

  • the TLS certificate is valid and contains the correct SAN
  • DNS resolves to a single IPv4 address
  • the same upload works when performed via fetch() in Bun
  • the same minio.putObject() code works correctly in Node.js v24.4.1

Minio is hosted on port 9002 and there is no LB or proxy so i hitting https://mydomain.com:9002 directly

It works okay with node. This strongly suggests a Bun ↔ MinIO client TLS compatibility issue, likely related to Bun’s Node compatibility layer or HTTP/TLS agent behavior.


Environment

  • Bun version: 1.3.6

  • Node version (working): v24.4.1

  • MinIO client: minio@8.0.6

  • OS: Linux (Docker)

  • Docker image: oven/bun:1-slim

  • TLS: HTTPS with valid certificate

    • SAN includes DNS:mydomain.com
    • Verified via openssl s_client
  • DNS: Single A record (no IPv6, no round-robin)


What works ✅

1. Plain fetch() GET in Bun

await fetch("https://mydomain.com:9002/webapp-images/event/test.webp");

2. Plain fetch() PUT in Bun

await fetch("https://mydomain.com:9002/webapp-images/event/test.webp", {
  method: "PUT",
  body: buffer,
});

3. MinIO presigned PUT URL + fetch() in Bun

  • minio.presignedPutObject() works
  • Uploading to that URL with fetch() works

4. Same minio.putObject() code works in Node.js v24.4.1


What fails ❌

minioClient.putObject() in Bun

Minimal repro (fails only in Bun):

import * as Minio from "minio";
import { readFileSync } from "node:fs";

const client = new Minio.Client({
  endPoint: "mydomain.com",
  port: 9002,
  useSSL: true,
  accessKey: process.env.MINIO_ACCESS_KEY,
  secretKey: process.env.MINIO_SECRET_KEY,
  region: "eu-central-2",
});

const buf = readFileSync("./test.webp");

await client.putObject(
  "webapp-images",
  `event/bun-putobject-${Date.now()}.webp`,
  buf,
  buf.length,
  { "Content-Type": "image/webp" },
);

Error

FAIL ERR_TLS_CERT_ALTNAME_INVALID fetching "https://mydomain.com:9002/webapp-images/event/bun-putobject-1768988449282.webp". For more information, pass `verbose: true` in the second argument to fetch()

TLS verification sanity checks

openssl s_client -connect mydomain.com:9002 -servername mydomain.com

Result:

X509v3 Subject Alternative Name:
  DNS:*.mydomain.com, DNS:mydomain.com

DNS:

getent ahosts mydomain.com
# single IPv4 address only

Workaround

Use presignedPutObject() + fetch() for uploads, or NODE_TLS_REJECT_UNAUTHORIZED=0.
This avoids the issue entirely but is not ideal, as putObject() should work.

Additional notes

  • No proxies (HTTP_PROXY, HTTPS_PROXY) are set
  • No custom CA bundles (NODE_EXTRA_CA_CERTS, SSL_CERT_FILE)
  • Same container, same network, same cert
  • It appears the node:https shim is likely passing mydomain.com:9002 to the TLS validator instead of just mydomain.com

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions