sipeed/picoclaw · warning

missing flow id

Error message

missing flow id

What it means

Returned as HTTP 400 by GET /api/oauth/flows/{id} when the path value trims to empty. Because the route is registered as "GET /api/oauth/flows/{id}" on a Go 1.22+ ServeMux, a truly empty segment does not match the pattern at all; you reach this check only when the id consists of whitespace (URL-encoded, e.g. %20) that strings.TrimSpace strips. It is a defensive guard against malformed client-built URLs.

Source

Thrown at web/backend/api/oauth.go:324

		w.Header().Set("Content-Type", "application/json")
		_ = json.NewEncoder(w).Encode(map[string]any{
			"status":     "ok",
			"provider":   provider,
			"method":     method,
			"flow_id":    flow.ID,
			"auth_url":   authURL,
			"expires_at": flow.ExpiresAt.Format(time.RFC3339),
		})
		return
	default:
		http.Error(w, "unsupported login method", http.StatusBadRequest)
	}
}

func (h *Handler) handleGetOAuthFlow(w http.ResponseWriter, r *http.Request) {
	flowID := strings.TrimSpace(r.PathValue("id"))
	if flowID == "" {
		http.Error(w, "missing flow id", http.StatusBadRequest)
		return
	}

	flow, ok := h.getOAuthFlow(flowID)
	if !ok {
		http.Error(w, "flow not found", http.StatusNotFound)
		return
	}

	w.Header().Set("Content-Type", "application/json")
	_ = json.NewEncoder(w).Encode(flowToResponse(flow))
}

func (h *Handler) handlePollOAuthFlow(w http.ResponseWriter, r *http.Request) {
	flowID := strings.TrimSpace(r.PathValue("id"))
	if flowID == "" {
		http.Error(w, "missing flow id", http.StatusBadRequest)
		return

View on GitHub (pinned to 49183d7e8d)

Solutions

  1. Always use the exact flow_id string returned by POST /api/oauth/login in the URL.
  2. Client-side, reject or skip the request when flowId is empty or whitespace before building the URL.
  3. URL-encode the id (encodeURIComponent) so spaces cannot slip in unnoticed.

Example fix

// before
const url = `/api/oauth/flows/${flowId ?? ' '}`; // placeholder whitespace -> 400 missing flow id

// after
if (!flowId?.trim()) throw new Error('No OAuth flow in progress');
const url = `/api/oauth/flows/${encodeURIComponent(flowId)}`;
Defensive patterns

Strategy: validation

Validate before calling

function flowUrl(flowId) {
  const id = String(flowId ?? '').trim();
  if (!id) throw new Error('missing flow id');
  return `/api/oauth/flows/${encodeURIComponent(id)}`;
}

Type guard

function isFlowId(v) { return typeof v === 'string' && v.trim().length > 0; }

Prevention

When it happens

Trigger: GET /api/oauth/flows/%20 or /api/oauth/flows/%09 — an id that exists in the path but is whitespace-only after decoding/trimming.

Common situations: Clients interpolating an unvalidated/undefined flow id into the URL template; template engines emitting a space placeholder; copy-paste artifacts in manual curl tests.

Related errors


AI-assisted analysis of sipeed/picoclaw@49183d7e8d (2026-08-15). Data as JSON: /api/errors/8fda7a6e161b6bfc. Report an issue: GitHub.