tailscale/tailscale · error

can't parse expiry time, expects a unix timestamp

Error message

can't parse expiry time, expects a unix timestamp

What it means

Sent as 400 by serveSetExpirySooner when the 'expiry' parameter is present but not an integer Unix timestamp.

Source

Thrown at ipn/localapi/localapi.go:1246

}

// serveSetExpirySooner sets the expiry date on the current machine, specified
// by an `expiry` unix timestamp as POST or query param.
func (h *Handler) serveSetExpirySooner(w http.ResponseWriter, r *http.Request) {
	if !h.PermitWrite {
		http.Error(w, "access denied", http.StatusForbidden)
		return
	}
	if r.Method != httpm.POST {
		http.Error(w, "POST required", http.StatusMethodNotAllowed)
		return
	}

	var expiryTime time.Time
	if v := r.FormValue("expiry"); v != "" {
		expiryInt, err := strconv.ParseInt(v, 10, 64)
		if err != nil {
			http.Error(w, "can't parse expiry time, expects a unix timestamp", http.StatusBadRequest)
			return
		}
		expiryTime = time.Unix(expiryInt, 0)
	} else {
		http.Error(w, "missing 'expiry' parameter, a unix timestamp", http.StatusBadRequest)
		return
	}
	err := h.b.SetExpirySooner(r.Context(), expiryTime)
	if err != nil {
		http.Error(w, err.Error(), http.StatusBadRequest)
		return
	}
	w.Header().Set("Content-Type", "text/plain")
	io.WriteString(w, "done\n")
}

func (h *Handler) servePing(w http.ResponseWriter, r *http.Request) {
	ctx := r.Context()

View on GitHub (pinned to 6e0912f979)

Solutions

  1. Pass expiry as seconds since Unix epoch (e.g. 1735689600)
  2. Remove quotes/whitespace from the parameter
  3. Validate client-side before sending
Defensive patterns

Strategy: validation

When it happens

Trigger: Thrown at ipn/localapi/localapi.go:1246 when the library encounters an invalid state.

Common situations: See trigger scenarios.


AI-assisted analysis of tailscale/tailscale@6e0912f979 (2026-08-18). Data as JSON: /api/errors/174bbaf91271cdde. Report an issue: GitHub.