How TeslaMate Handles API Rate Limits: Detection, Retry Logic, and Back-Off Strategy

TeslaMate detects HTTP 429 responses from the Tesla Owner API, extracts the Retry-After header value (defaulting to 300 seconds), and propagates a structured error tuple that allows the application to back off gracefully without spamming the API.

When ingesting data from the Tesla Owner API, TeslaMate must respect global rate limits to maintain reliable access. According to the teslamate-org/teslamate source code, the application implements a robust strategy to detect HTTP 429 "Too Many Requests" responses, parse retry delays, and propagate structured errors through the Elixir call stack.

How TeslaMate Detects Rate Limit Responses

The detection logic resides in lib/tesla_api/vehicle.ex within the TeslaApi.Vehicle.handle_response/2 function. This private function pattern matches on the Tesla HTTP client response, specifically looking for %Tesla.Env{status: 429, headers: headers}.

When a match occurs, the code extracts the Retry-After header to determine how long to wait before the next request.


# Detecting a 429 response (TeslaApi.Vehicle)

defp handle_response({:ok, %Tesla.Env{} = env}, opts) do
  case env do
    %Tesla.Env{status: 429, headers: headers} ->
      retry_after =
        case Enum.find(headers, fn {k, _} -> k == "retry-after" end) do
          nil   -> "300"
          {"retry-after", v} -> v
        end

      {:error,
       %Error{reason: :too_many_request, message: String.to_integer(retry_after)}}
    # … other clauses …

  end
end

Extracting the Retry-After Header

The extraction logic scans the response headers for the "retry-after" key. If the header is absent, TeslaMate defaults to 300 seconds (5 minutes) as a conservative back-off period.

The function converts the header value to an integer and wraps it in a custom %Error{} struct with the reason :too_many_request and the retry seconds stored in the message field. This creates a type-safe error that propagates through the functional call chain.

Error Propagation and Logging

In lib/teslamate/api.ex, the Teslamate.Api.handle_result/3 function consumes the %TeslaApi.Error{} struct. When it encounters reason: :too_many_request, it logs a warning message containing the retry delay and forwards a normalized tuple {:error, :too_many_request, retry_seconds} to calling processes.

This centralized handling ensures consistent logging across the application while providing callers with the specific back-off interval required by the Tesla API.


# Propagating the error (Teslamate.Api)

defp handle_result(result, _auth, _name) do
  case result do
    {:error, %TeslaApi.Error{reason: :too_many_request, message: retry_after}} ->
      Logger.warning("TeslaApi.Error / :too_many_request #{retry_after}")
      {:error, :too_many_request, retry_after}
    # … other clauses …

  end
end

Implementing Back-Off in Calling Code

Higher-level modules such as lib/teslamate/vehicles/vehicle.ex receive the error tuple and implement appropriate back-off strategies. Callers can use Process.send_after/3 to schedule retries after the specified interval, preventing request spam while respecting server-defined limits.


# Using the retry interval (example caller)

case Teslamate.Api.some_call(...) do
  {:error, :too_many_request, wait_secs} ->
    # back‑off before next attempt

    Process.send_after(self(), :retry_request, wait_secs * 1_000)
  {:ok, data} ->
    # normal processing

    …
end

Summary

  • TeslaMate detects HTTP 429 responses in TeslaApi.Vehicle.handle_response/2 by pattern matching on the status code.
  • The Retry-After header is extracted from the response, defaulting to 300 seconds if not present.
  • Errors propagate as {:error, :too_many_request, retry_seconds} through Teslamate.Api.handle_result/3.
  • The application logs rate limit incidents with the specific delay value for observability.
  • Calling code uses the retry interval to implement non-blocking back-off strategies.

Frequently Asked Questions

What happens when TeslaMate encounters an HTTP 429 error?

When the Tesla Owner API returns HTTP 429, TeslaMate extracts the Retry-After header value and returns a structured error tuple containing the exact number of seconds to wait. This prevents the application from immediately retrying the request and potentially exacerbating the rate limit.

Where does TeslaMate extract the retry delay from?

The retry delay is extracted from the Retry-After HTTP response header in lib/tesla_api/vehicle.ex. If this header is missing, the system defaults to a 300-second back-off period to ensure safe operation.

How does TeslaMate avoid spamming the Tesla API during rate limiting?

TeslaMate avoids spamming by respecting the server-defined back-off interval. When Teslamate.Api.handle_result/3 detects a rate limit error, it logs a warning and forwards the retry delay to calling processes, which can then schedule delayed retries using Process.send_after/3 or similar mechanisms.

What is the default back-off period if no Retry-After header is present?

If the Tesla API response does not include a Retry-After header, TeslaMate defaults to 300 seconds (5 minutes) as the retry interval. This conservative default ensures compliance with API limits while maintaining data ingestion continuity.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →