larksuite/cli · error

Device authorization failed: %s

Error message

Device authorization failed: %s

What it means

The device-authorization endpoint responded with JSON, but the payload carries an OAuth error field (or the HTTP status is >=400). The server's error_description or error string is surfaced directly after the 'Device authorization failed:' prefix, falling back to 'Unknown error'.

Source

Thrown at internal/auth/device_flow.go:119

	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")
	verificationUriComplete := getStr(data, "verification_uri_complete")
	if verificationUriComplete == "" {
		verificationUriComplete = verificationUri
	}

	return &DeviceAuthResponse{
		DeviceCode:              getStr(data, "device_code"),
		UserCode:                getStr(data, "user_code"),
		VerificationUri:         verificationUri,
		VerificationUriComplete: verificationUriComplete,
		ExpiresIn:               expiresIn,
		Interval:                interval,

View on GitHub (pinned to 7fd6ef3c07)

Solutions

  1. Read the embedded server message (error_description) — it names the OAuth error such as invalid_client or unauthorized_client.
  2. Confirm the app's client_id/credentials in the Feishu/Lark developer console.
  3. Enable the device authorization grant / relevant scopes for the app and get tenant admin approval if required.
  4. If the message is 'Unknown error', capture the raw response and the HTTP status to debug further.
Defensive patterns

Strategy: try-catch

Type guard

func isDeviceAuthRejected(err error) bool {
    return err != nil && strings.HasPrefix(err.Error(), "Device authorization failed: ")
}

Try / catch

resp, err := auth.RequestDeviceAuthorization(ctx, clientID, scopes)
if err != nil {
    if isDeviceAuthRejected(err) {
        // surface the embedded OAuth error (error_description) to the user
        return fmt.Errorf("fix app config/grant type before retrying: %w", err)
    }
    return err
}

Prevention

When it happens

Trigger: RequestDeviceAuthorization sees resp.StatusCode >= 400 or data["error"] present — e.g. invalid client_id, unauthorized_client, access_denied, or the app is not enabled for device flow (grant type not allowed).

Common situations: App credentials (client_id) wrong or app deleted; device-grant type not enabled in the Lark/Feishu developer console; tenant admin disabled the app or scopes; expired/misconfigured app configuration after a version change.

Related errors


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