larksuite/cli · error

Device authorization failed: HTTP %d – response not JSON

Error message

Device authorization failed: HTTP %d – response not JSON

What it means

RequestDeviceAuthorization parsed the device-authorization endpoint's body as JSON and json.Unmarshal failed. Either the server returned non-JSON (HTML error page, empty body, gateway message) or the body was truncated. The HTTP status is embedded in the message to hint at the source.

Source

Thrown at internal/auth/device_flow.go:107

	}
	req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
	req.Header.Set("Authorization", "Basic "+basicAuth)

	resp, err := httpClient.Do(req)
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()
	logHTTPResponse(resp)

	body, err := io.ReadAll(resp.Body)
	if err != nil {
		return nil, fmt.Errorf("Device authorization failed: read body: %v", err)
	}

	var data map[string]interface{}
	if err := json.Unmarshal(body, &data); err != nil {
		return nil, fmt.Errorf("Device authorization failed: HTTP %d – response not JSON", resp.StatusCode)
	}

	_, hasError := data["error"]
	if resp.StatusCode >= 400 || hasError {
		msg := getStr(data, "error_description")
		if msg == "" {
			msg = getStr(data, "error")
		}
		if msg == "" {
			msg = "Unknown error"
		}
		return nil, fmt.Errorf("Device authorization failed: %s", msg)
	}

	expiresIn := getInt(data, "expires_in", 240)
	interval := getInt(data, "interval", 5)

	verificationUri := getStr(data, "verification_uri")

View on GitHub (pinned to 7fd6ef3c07)

Solutions

  1. Check the HTTP status in the message: 4xx/5xx from a gateway usually means the request never reached the auth service — verify network/proxy settings.
  2. Verify the base URL / endpoint configuration points at open.feishu.cn.
  3. Log or dump the raw body (before unmarshal) to see what was actually returned.
  4. Retry after confirming connectivity; a transient gateway page will disappear on retry.
Defensive patterns

Strategy: validation

Validate before calling

// preflight: verify the device-auth endpoint returns JSON before starting the flow
resp, _ := http.Get(deviceAuthURL)
b, _ := io.ReadAll(io.LimitReader(resp.Body, 512))
if !json.Valid(b) && resp.StatusCode != http.StatusOK {
    log.Fatalf("endpoint not returning JSON (HTTP %d): %.200s", resp.StatusCode, b)
}

Type guard

func isNonJSONDeviceAuthErr(err error) bool {
    return err != nil && strings.Contains(err.Error(), "response not JSON")
}

Try / catch

resp, err := auth.RequestDeviceAuthorization(ctx, clientID, scopes)
if isNonJSONDeviceAuthErr(err) {
    return fmt.Errorf("gateway/proxy returned non-JSON; check network and base URL: %w", err)
}

Prevention

When it happens

Trigger: json.Unmarshal(body, &data) returns an error in RequestDeviceAuthorization — e.g. an LB/gateway returns an HTML 502 page, an empty 200 body, or the endpoint is blocked and a captive portal responds.

Common situations: Corporate proxy returning an HTML block page for open.feishu.cn; wrong base URL/endpoint override pointing at a non-Lark server; gateway outage serving plain-text error pages.

Related errors


AI-assisted analysis of larksuite/cli@7fd6ef3c07 (2026-09-04). Data as JSON: /api/errors/e1c09798a4a22266. Report an issue: GitHub.