Skip to content

Expired SSL Certificate on external MQTT server causes TeslaMate to crash #4944

@rhayre

Description

@rhayre

Is there an existing issue for this?

  • I have checked the existing issues and discussions, and I can confirm that there are no duplicates.

What happened?

I've had TeslaMate setup to publish information to an external MQTT Server for Home Assistant, and it's been working fine for a month or so with no issues. My external MQTT server supports TLS/SSL, so I configured TeslaMate to connect to it via TLS/SSL.

I logged into TeslaMate to view a recent trip, noticed no drives have been logged in the past week and there are 6000+ rows of incomplete drives. Looking into the logs, it appears that TeslaMate is crashing due to the external MQTT SSL Certificate expiring, restarting and repeating the crash.

One of the crash messages is attached below and repeats multiple times per minute. I did replace some of the private/unique data in the logs with <XXXXXX>.

The certificate on the external server did expire (script to restart the service after renewing the certs failed to run).

Expected Behavior

Since MQTT doesn't appear to be required for TeslaMate to gather and log Tesla data, I would expect the MQTT connection to fail, an error to be logged, but TeslaMate continue to run and gather data.

Alternatively, TeslaMate shouldn't log to the database until after the MQTT connection has been made to avoid incomplete drives.

I know this is a bit of an edge case, but it seems like any kind of MQTT connection failure will crash TeslaMate. There were a few similar issues I found (Issue #4840 and #4725), but none mention the incomplete drives.

Can the issue reliably be reproduced?

Yes

Steps To Reproduce the issue

No response

Relevant log output

teslamate-1  | 2025-09-09 00:14:47.278 [info] Migrations already up
teslamate-1  | 2025-09-09 00:14:49.600 [info] System Info: Erlang/OTP 26 (jit)
teslamate-1  | 2025-09-09 00:14:49.600 [info] Version: 2.1.1
teslamate-1  | PostgreSQL version 17.6 is compatible (17.x series).
teslamate-1  | 2025-09-09 00:14:50.041 [info] POST https://auth.tesla.com/oauth2/v3/token -> 200 (332.965 ms)
teslamate-1  | 2025-09-09 00:14:50.041 [info] Refreshed api tokens
teslamate-1  | 2025-09-09 00:14:50.049 [info] Scheduling token refresh in 6 h
teslamate-1  | 2025-09-09 00:14:50.057 [info] Running TeslaMateWeb.Endpoint with cowboy 2.13.0 at :::4000 (http)
teslamate-1  | 2025-09-09 00:14:50.059 [info] Access TeslaMateWeb.Endpoint at http://teslamate.<XXXXXX>.com
teslamate-1  | 2025-09-09 00:14:50.708 [info] Starting logger for '<XXXXXX>'
teslamate-1  | 2025-09-09 00:14:50.713 [info] Starting logger for '<XXXXXX>'
teslamate-1  | 2025-09-09 00:14:50.868 car_id=2 [info] Start / :offline
teslamate-1  | 2025-09-09 00:14:51.152 car_id=4 [info] Start / :online
teslamate-1  | 2025-09-09 00:14:51.171 car_id=4 [info] Stream connecting ...
teslamate-1  | 2025-09-09 00:14:51.335 [notice] TLS :client: In state :wait_cert_cr at ssl_handshake.erl:2124 generated CLIENT ALERT: Fatal - Certificate Expired
teslamate-1  |
teslamate-1  | 2025-09-09 00:14:51.336 [warning] [Tortoise311] Connection failed: {:tls_alert, {:certificate_expired, ~c"TLS client: In state wait_cert_cr at ssl_handshake.erl:2124 generated CLIENT ALERT: Fatal - Certificate Expired\n"}}, %{port: 8883, status: :down, protocol: "MQTT", host: ~c"homeassistant.<XXXXXX>.com", protocol_version: 4, keep_alive: 60, transport: Tortoise311.Transport.SSL, subscriptions: %Tortoise311.Package.Subscribe{__META__: %Tortoise311.Package.Meta{opcode: 8, flags: 2}, identifier: nil, topics: []}, client_id: "TESLAMATE_<XXXXXX>", clean_session: true}. Retrying in 100 msecs.
teslamate-1  | 2025-09-09 00:14:51.336 [error] GenServer {Tortoise311.Registry, {Tortoise311.Connection, "TESLAMATE_<XXXXXX>"}} terminating
teslamate-1  | ** (stop) {:tls_alert, {:certificate_expired, ~c"TLS client: In state wait_cert_cr at ssl_handshake.erl:2124 generated CLIENT ALERT: Fatal - Certificate Expired\n"}}
teslamate-1  | Last message: :connect
teslamate-1  | 2025-09-09 00:15:00.224 [warning] [Tortoise311] Connection - timed out
teslamate-1  | 2025-09-09 00:15:00.224 [error] GenServer TeslaMate.Mqtt.Publisher terminating
teslamate-1  | ** (MatchError) no match of right hand side value: {:error, :timeout}
teslamate-1  |     (teslamate 2.1.1) lib/teslamate/mqtt/publisher.ex:41: TeslaMate.Mqtt.Publisher.handle_call/3
teslamate-1  |     (stdlib 5.2.3.4) gen_server.erl:1131: :gen_server.try_handle_call/4
teslamate-1  |     (stdlib 5.2.3.4) gen_server.erl:1160: :gen_server.handle_msg/6
teslamate-1  |     (stdlib 5.2.3.4) proc_lib.erl:241: :proc_lib.init_p_do_apply/3
teslamate-1  | Last message (from #PID<0.2728.0>): {:publish, "teslamate/cars/2/healthy", "", [retain: true, qos: 1]}
teslamate-1  | 2025-09-09 00:15:05.272 [notice] Application teslamate exited: TeslaMate.Application.start(:normal, []) returned an error: shutdown: failed to start child: TeslaMate.Mqtt
teslamate-1  |     ** (EXIT) shutdown: failed to start child: TeslaMate.Mqtt.PubSub
teslamate-1  |         ** (EXIT) shutdown: failed to start child: TeslaMate.Mqtt.PubSub.VehicleSubscriber2
teslamate-1  |             ** (EXIT) exited in: GenServer.call(TeslaMate.Mqtt.Publisher, {:publish, "teslamate/cars/2/healthy", "", [retain: true, qos: 1]}, 10000)
teslamate-1  |                 ** (EXIT) an exception was raised:
teslamate-1  |                     ** (MatchError) no match of right hand side value: {:error, :timeout}
teslamate-1  |                         (teslamate 2.1.1) lib/teslamate/mqtt/publisher.ex:41: TeslaMate.Mqtt.Publisher.handle_call/3
teslamate-1  |                         (stdlib 5.2.3.4) gen_server.erl:1131: :gen_server.try_handle_call/4
teslamate-1  |                         (stdlib 5.2.3.4) gen_server.erl:1160: :gen_server.handle_msg/6
teslamate-1  |                         (stdlib 5.2.3.4) proc_lib.erl:241: :proc_lib.init_p_do_apply/3
teslamate-1  | Kernel pid terminated (application_controller) ("{application_start_failure,teslamate,{{shutdown,{failed_to_start_child,'Elixir.TeslaMate.Mqtt',{shutdown,{failed_to_start_child,'Elixir.TeslaMate.Mqtt.PubSub',{shutdown,{failed_to_start_child,'Elixir.TeslaMate.Mqtt.PubSub.VehicleSubscriber2',{{{badmatch,{error,timeout}},[{'Elixir.TeslaMate.Mqtt.Publisher',handle_call,3,[{file,\"lib/teslamate/mqtt/publisher.ex\"},{line,41}]},{gen_server,try_handle_call,4,[{file,\"gen_server.erl\"},{line,1131}]},{gen_server,handle_msg,6,[{file,\"gen_server.erl\"},{line,1160}]},{proc_lib,init_p_do_apply,3,[{file,\"proc_lib.erl\"},{line,241}]}]},{'Elixir.GenServer',call,['Elixir.TeslaMate.Mqtt.Publisher',{publish,<<\"teslamate/cars/2/healthy\">>,<<>>,[{retain,true},{qos,1}]},10000]}}}}}}}},{'Elixir.TeslaMate.Application',start,[normal,[]]}}}")
teslamate-1  |
teslamate-1  | Crash dump is being written to: erl_crash.dump...done

Screenshots

No response

Additional data

This issue also causes a lot of requests to be sent to Tesla's API since every time TeslaMate starts, it sends a POST request to authenticate every time it starts. I'm surprised Tesla didn't rate-limit or ban my IP due to this.

$ docker compose logs teslamate | awk '/2025-09/ && /POST https:\/\/auth.tesla.com\/oauth2/ {print$3}' | sort | uniq -c
   5209 2025-09-01
   5229 2025-09-02
   5293 2025-09-03
   5260 2025-09-04
   5223 2025-09-05
   5293 2025-09-06
   5198 2025-09-07
   5215 2025-09-08
     43 2025-09-09

Type of installation

Docker (https://docs.teslamate.org/docs/installation/docker/)

Version

v2.1.1

PostgreSQL version

v17

Are you running latest major supported PostgreSQL version?

  • I run the latest major supported PostgreSQL version

Are you using a reverse Proxy for TeslaMate?

Yes (specify in next field)

Details about your reverse Proxy if applicable

Traefik, but not relevant to the MQTT issue seen above.

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