WARNING:livekit:livekit::rtc_engine:401:livekit::r...
# ask-ai
r
WARNINGlivekitlivekit:rtc engine401livekit:rtc_engine - failed to connect: Signal(RegionError("error sending request for url (https://gemini-live-api-test-o7e8z3sr.livekit.cloud/settings/regions)")), retrying... (1/3) WARNINGlivekitlivekit:rtc engine401livekit:rtc_engine - failed to connect: Signal(RegionError("error sending request for url (https://gemini-live-api-test-o7e8z3sr.livekit.cloud/settings/regions)")), retrying... (1/3) {"level": "WARNING", "name": "livekit", "message": "livekit:rtc engine401livekit:rtc_engine - failed to connect: Signal(RegionError(\"error sending request for url (https://gemini-live-api-test-o7e8z3sr.livekit.cloud/settings/regions)\")), retrying... (1/3)", "pid": 1182, "job_id": "AJ_tsZxzw3ezuaE", "room_id": "RM_NeTVMZB5ae9u", "timestamp": "2025-12-16T110529.539726+00:00"} WARNINGlivekitlivekit:rtc engine401livekit:rtc_engine - failed to connect: Signal(RegionError("error sending request for url (https://gemini-live-api-test-o7e8z3sr.livekit.cloud/settings/regions)")), retrying... (2/3) {"level": "WARNING", "name": "livekit", "message": "livekit:rtc engine401livekit:rtc_engine - failed to connect: Signal(RegionError(\"error sending request for url (https://gemini-live-api-test-o7e8z3sr.livekit.cloud/settings/regions)\")), retrying... (2/3)", "pid": 1182, "job_id": "AJ_tsZxzw3ezuaE", "room_id": "RM_NeTVMZB5ae9u", "timestamp":
t
Thanks for reaching out, Gaurav. I'm an AI assistant and I'm here to help. Give me a moment while I research this topic.
Thanks — I see you're getting repeated "failed to connect: Signal(RegionError(.../settings/regions))" warnings for job_id
AJ_tsZxzw3ezuaE
, room
RM_NeTVMZB5ae9u
. That means the client/agent cannot reach the LiveKit regions discovery endpoint. Let's narrow this down and get you back online. Please try these checks and tell me the results for each: 1. From the host running the client/agent, run:
Copy code
curl -v <https://gemini-live-api-test-o7e8z3sr.livekit.cloud/settings/regions>
• Does it return JSON or an HTTP error/timeout? If there is an SSL error, paste the first few lines of output. 1. DNS and basic network: ◦ Can you resolve the domain? (e.g.,
nslookup gemini-live-api-test-o7e8z3sr.livekit.cloud
or
dig
) ◦ Can you reach port 443? (e.g.,
telnet gemini-live-api-test-o7e8z3sr.livekit.cloud 443
or
openssl s_client -connect ...:443
) 1. Firewall / proxy / corporate inspection: ◦ Are you behind Zscaler, a corporate proxy, or a firewall that does TLS inspection? If yes, try connecting from a different network (mobile hotspot or home) to confirm if the environment blocks it. ◦ If Zscaler/proxy is used, can you whitelist
gemini-live-api-test-o7e8z3sr.livekit.cloud
and allow WSS/HTTPS traffic without deep packet inspection? 1. Server health and TLS: ◦ Is your LiveKit server confirmed running and healthy at that hostname? Do you have a valid TLS certificate (not self-signed) trusted by the client? 1. Region pinning / configuration: ◦ Are you using protocol-based region pinning for this project? If yes, confirm it was enabled for the project and that the pinned region is operational. If unsure, try disabling region pinning temporarily and retry. 1. Logs and timing: ◦ Does the failure happen instantly or after a timeout? Share any additional client logs around the same timestamp if possible. If you share the curl output (or the DNS / openssl results) and whether the environment uses a proxy/firewall, I’ll recommend the exact next step. Would you like guidance running any of the commands above? Sources: Distributed Setup | LiveKit docs | Diagnosing Connection Errors with Connection Test Utility | Configuring firewalls | LiveKit docs | Zscaler proxy configuration | Region pinning | LiveKit docs
r
the failure is happening from inside a docker container
t
Thanks — since this is happening inside a Docker container, let's check container-specific networking and TLS behavior. Please run these from inside the failing container and share the outputs (or any errors): 1. DNS resolution
Copy code
nslookup gemini-live-api-test-o7e8z3sr.livekit.cloud
1. HTTPS connectivity + headers
Copy code
curl -v <https://gemini-live-api-test-o7e8z3sr.livekit.cloud/settings/regions>
1. TLS handshake details
Copy code
openssl s_client -connect gemini-live-api-test-o7e8z3sr.livekit.cloud:443 -servername gemini-live-api-test-o7e8z3sr.livekit.cloud </dev/null 2>&1 | sed -n '1,120p'
1. Check network mode and routes (from host and container) • On the host:
docker inspect -f '{{.HostConfig.NetworkMode}}' <container>
• Inside container:
ip route
and
cat /etc/resolv.conf
1. If you use a corporate proxy or TLS-inspecting appliance: • Is the container configured with `HTTP_PROXY`/`HTTPS_PROXY`/`NO_PROXY` env vars? • Does the host inject a custom CA into containers? If TLS is intercepted, the container needs the proxy’s CA in its trust store. 1. Test from host network (to compare) • Run the same curl from the Docker host (not inside the container). If host succeeds but container fails, this confirms container network or DNS/proxy settings are the cause. Share the command outputs and whether the host curl succeeds. I’ll use those results to give exact next steps (DNS fix, proxy envs, CA import, or network-mode change).
r
root@docker-desktop:/# curl -v https://gemini-live-api-test-o7e8z3sr.livekit.cloud/settings/regions * Host gemini-live-api-test-o7e8z3sr.livekit.cloud:443 was resolved. * IPv6: (none) * IPv4: 143.223.91.6, 143.223.91.134 * Trying 143.223.91.6:443... * ALPN: curl offers h2,http/1.1 * TLSv1.3 (OUT), TLS handshake, Client hello (1): * CAfile: /etc/ssl/certs/ca-certificates.crt * CApath: /etc/ssl/certs * TLSv1.3 (IN), TLS handshake, Server hello (2): * TLSv1.3 (IN), TLS change cipher, Change cipher spec (1): * TLSv1.3 (IN), TLS handshake, Encrypted Extensions (8): * TLSv1.3 (IN), TLS handshake, Certificate (11): * TLSv1.3 (OUT), TLS alert, unknown CA (560): * SSL certificate problem: self-signed certificate in certificate chain * closing connection #0 curl: (60) SSL certificate problem: self-signed certificate in certificate chain More details here: https://curl.se/docs/sslcerts.html curl failed to verify the legitimacy of the server and therefore could not establish a secure connection to it. To learn more about this situation and how to fix it, please visit the webpage mentioned above.\
t
Thanks — the curl output shows the TLS handshake fails with "self-signed certificate in certificate chain." That explains the RegionError: the container does not trust the server certificate. You can fix this in one of these safe ways (pick the one that matches your environment): • Add the signing CA to the container's trusted store (recommended for corporate / intercepted TLS): a. Copy the CA certificate (PEM) into the container (e.g.,
/usr/local/share/ca-certificates/my-proxy.crt
). b. Run inside the container:
Copy code
update-ca-certificates
1. Restart the service/process using LiveKit. • If the container image is rebuilt frequently, bake the CA into the image in Dockerfile:
Copy code
COPY my-proxy.crt /usr/local/share/ca-certificates/
  RUN update-ca-certificates
• For quick testing only: skip verification (not for production) ◦ curl:
curl -k https://.../settings/regions
◦ If the LiveKit client has an option to disable TLS verification for testing, use that temporarily. • Replace the server certificate with one trusted by public CAs: ◦ Install a certificate from a public CA (Let’s Encrypt or similar) on
gemini-live-api-test-o7e8z3sr.livekit.cloud
so clients trust it without custom CAs. Additional checks: • If you’re behind a TLS-intercepting proxy (Zscaler, corporate DPI), ensure the proxy’s CA is the one you add to the container. • After adding the CA, re-run:
Copy code
curl -v <https://gemini-live-api-test-o7e8z3sr.livekit.cloud/settings/regions>
and confirm you get a JSON response instead of the SSL error. Which option would you like help with? If you share the container base image (e.g., debian, alpine, ubuntu) I’ll give exact commands to install the CA into that image.
r
Copy code
package com.livekit.tokenserver;

import com.fasterxml.jackson.databind.ObjectMapper;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.security.Keys;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.*;

import javax.crypto.SecretKey;
import java.nio.charset.StandardCharsets;
import java.time.Instant;
import java.util.*;

@RestController
@CrossOrigin(origins = "*")
public class TokenController {

    @Value("${livekit.url}")
    private String livekitUrl;

    @Value("${livekit.api-key}")
    private String apiKey;

    @Value("${livekit.api-secret}")
    private String apiSecret;

    @Value("${livekit.default-room}")
    private String defaultRoom;

    @Value("${livekit.default-agent-name}")
    private String defaultAgentName;

    private final ObjectMapper objectMapper = new ObjectMapper();

    @GetMapping("/token")
    public Map<String, Object> generateToken(
            @RequestParam(defaultValue = "en-IN") String language,
            @RequestParam(defaultValue = "Aoede") String voice,
            @RequestParam(required = false) String room) {

        String userId = generateUserId();
        String identity = "user-" + userId;
        String roomName = (room != null && !room.isEmpty()) ? room : defaultRoom;

        String token = createAccessToken(identity, userId, roomName, language, voice);

        Map<String, Object> response = new HashMap<>();
        response.put("token", token);
        response.put("url", livekitUrl);
        response.put("room", roomName);
        response.put("identity", identity);
        response.put("language", language);
        response.put("voice", voice);

        System.out.println("✓ Generated token for " + identity + " (Language: " + language + ", Voice: " + voice + ")");

        return response;
    }

    @GetMapping("/health")
    public Map<String, String> health() {
        Map<String, String> status = new HashMap<>();
        status.put("status", "UP");
        status.put("service", "livekit-token-service");
        return status;
    }

    private String createAccessToken(String identity, String userId, String room, String language, String voice) {
        try {
            SecretKey secretKey = Keys.hmacShaKeyFor(apiSecret.getBytes(StandardCharsets.UTF_8));

            Instant now = Instant.now();
            Instant expiration = now.plusSeconds(3600);

            // Create metadata
            Map<String, Object> metadata = new HashMap<>();
            metadata.put("language", language);
            metadata.put("voice", voice);
            String metadataJson = objectMapper.writeValueAsString(metadata);

            // Create agent dispatch configuration
            Map<String, Object> agentMetadata = new HashMap<>();
            agentMetadata.put("language", language);
            agentMetadata.put("voice", voice);
            agentMetadata.put("user_id", identity);
            String agentMetadataJson = objectMapper.writeValueAsString(agentMetadata);

            Map<String, Object> agentDispatch = new HashMap<>();
            agentDispatch.put("agent_name", defaultAgentName);
            agentDispatch.put("metadata", agentMetadataJson);

            List<Map<String, Object>> agents = new ArrayList<>();
            agents.add(agentDispatch);

            Map<String, Object> roomConfig = new HashMap<>();
            roomConfig.put("agents", agents);

            // Build JWT token
            return Jwts.builder()
                    .header()
                        .add("typ", "JWT")
                        .add("alg", "HS256")
                    .and()
                    .issuer(apiKey)
                    .subject(identity)
                    .issuedAt(Date.from(now))
                    .expiration(Date.from(expiration))
                    .claim("name", "User " + userId)
                    .claim("video", Map.of(
                            "roomJoin", true,
                            "room", room,
                            "canPublish", true,
                            "canSubscribe", true
                    ))
                    .claim("metadata", metadataJson)
                    .claim("room_config", roomConfig)
                    .signWith(secretKey)
                    .compact();
        } catch (Exception e) {
            throw new RuntimeException("Failed to create access token", e);
        }
    }

    private String generateUserId() {
        String chars = "abcdefghijklmnopqrstuvwxyz0123456789";
        Random random = new Random();
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < 8; i++) {
            sb.append(chars.charAt(random.nextInt(chars.length())));
        }
        return sb.toString();
    }
}
t
Thanks — the curl output confirms a "self-signed certificate in certificate chain" inside the container. That’s why the LiveKit client sees RegionError: the container doesn’t trust the server certificate. To give exact commands, which base image is your container using (alpine, debian/ubuntu, or another)? Also tell me whether the certificate is from a corporate TLS-intercepting proxy (Zscaler/etc.) or a self-signed/private CA you control. I can then provide: • The precise Dockerfile / runtime steps to add the CA to the system trust store, and • If you need it, the exact commands to import the CA into the Java
cacerts
truststore for your token server. Sources: Configuring firewalls | LiveKit docs | Running LiveKit on AWS | Diagnosing Connection Errors with Connection Test Utility