larksuite/cli · error

Device authorization failed: HTTP

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.

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.

Appendix: 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)