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)
returnView on GitHub (pinned to 49183d7e8d)
Solutions
- Always use the exact flow_id string returned by POST /api/oauth/login in the URL.
- Client-side, reject or skip the request when flowId is empty or whitespace before building the URL.
- 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
- Only build flow URLs from the flow_id returned by POST /api/oauth/login.
- Always encodeURIComponent path parameters.
- Never substitute placeholders (spaces) for missing ids in URL templates.
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
- unsupported provider %q
- unsupported login method %q for provider %q
- token is required
- flow does not support polling
- MCP server ${server.name} requires a URL.
AI-assisted analysis of sipeed/picoclaw@49183d7e8d (2026-08-15).
Data as JSON: /api/errors/8fda7a6e161b6bfc.
Report an issue: GitHub.