Troubleshooting
401 with a fresh token
Section titled “401 with a fresh token”Symptom: You just signed in, but API calls return 401 Token expired or 401 Invalid token.
Causes:
- Clock skew. JWT validation checks
exp(expiration) against the server’s clock. If your device’s clock is more than a few minutes off, tokens may appear expired. Sync your system clock with NTP. - Token copied incorrectly. Make sure you’re using the full
access_tokenstring with no trailing whitespace or line breaks. - Wrong header format. The header must be exactly
Authorization: Bearer <access_token>— note the space afterBearerand no quotes around the token value. - Using the wrong token.
access_tokengoes in theAuthorizationheader.refresh_tokenis only for exchanging atPOST /auth/refresh.
Fix: Verify your system clock is accurate (date -u should match UTC within a few seconds). If the clock is fine, refresh your access token (see Authentication) and confirm the Authorization header is formatted correctly.
Access token expired
Section titled “Access token expired”Symptom: API calls were working, now they return 401 Token expired.
Cause: Access tokens last 1 hour. Your client needs to exchange the refresh token for a new access token before the current one expires.
Fix: Exchange your refresh token for a new access token:
curl -X POST https://api.hungrymachines.io/auth/refresh \ -H "Content-Type: application/json" \ -d '{"refresh_token": "YOUR_REFRESH_TOKEN"}'The response contains a new access_token and a new refresh_token — save both, then retry your original request with the new access token. If this call itself returns 400 Invalid Refresh Token, the refresh token is expired (30-day max) — the user needs to log in again.
Readings accepted but no schedule
Section titled “Readings accepted but no schedule”Symptom: POST /api/v1/readings returns 201 accepted, but GET /api/v1/schedule returns source: "defaults" with a flat comfort band and zero savings.
Cause: Hungry Machines needs about a few days of continuous readings before it can build a model of how your home responds. Until then, the schedule endpoint returns safe defaults based on your preferences and setpoint_temps is null.
What to expect:
- At first:
source: "defaults", flat comfort band,model_confidence: null,setpoint_temps: null. - After a few days: once enough continuous data has arrived, the next overnight run produces your first
source: "optimization"schedule. - Ongoing: Hungry Machines keeps the model current as it sees more weather and more of how your home responds.
Fix: Keep pushing readings consistently. The defaults are safe to apply — they maintain your comfort settings but won’t save energy. When source is "defaults", apply the band midpoint as your setpoint: (high_temps[idx] + low_temps[idx]) / 2. Once the model is ready, setpoint_temps becomes a 48-element array and optimized schedules appear automatically.
Schedule looks like flat setpoints
Section titled “Schedule looks like flat setpoints”Symptom: source is "optimization" but the high_temps and low_temps arrays have little variation — they look almost flat.
Causes:
- Savings level 1 (tight). With a ±2°F band, the optimizer has very little room to shift loads. Try increasing to savings level 2 (±6°F) or 3 (±12°F) via
PUT /api/v1/preferences. - Flat rate plan. If your utility charges the same rate all day, there’s no price signal to optimize against. The optimizer works best with time-of-use (TOU) or real-time pricing.
- Mild weather. When outdoor and indoor temps are close, the HVAC runs very little and there’s less to optimize.
Fix: Check your savings_level and optimization_mode in preferences. If you’re on a flat-rate plan, the optimizer may not produce significant schedule variation — that’s expected behavior, not a bug. You can inspect (and override) the rate curve the optimizer is using via GET / PUT /api/v1/rates — submitting your own 24-hour curve is the fastest way to give the optimizer a price signal to work with.
Appliance registration returns 403
Section titled “Appliance registration returns 403”Symptom: POST /api/v1/appliances returns 403 Upgrade required.
Cause: Free-tier accounts are limited to one HVAC appliance. You’ll get a 403 if you try to:
- Register a second appliance (any type)
- Register a non-HVAC device (EV charger, home battery, water heater)
Fix: Upgrade to Premium via the dashboard at hungrymachines.io/dashboard. Premium accounts can register unlimited appliances of any type.
Rate limit exceeded (429)
Section titled “Rate limit exceeded (429)”Symptom: POST /api/v1/readings returns 429 Rate limit exceeded.
Cause: The daily reading ceiling is a runaway-loop safeguard, not a normal-use limit. It scales with how many appliances you run — at 5-minute intervals a single HVAC generates ~288 readings/day, comfortably under the cap. Large catch-up batches after an outage, or an uncoordinated set of sensors all pushing at once, can trip it.
Fix: Push on a steady cadence rather than in bursts. If you’re catching up after an outage, spread the backfill out or trim to the most recent readings. If you legitimately run several appliances, tag each reading with its appliance_id — the ceiling scales with your active appliance count.
Still stuck?
Section titled “Still stuck?”If none of the above resolves your issue:
- File a bug on GitHub Issues — include the endpoint, request shape, and full error response.
- Email us at info@hungrymachines.io for account-specific issues.