Skip to content

fix: prevent silent exits on error (#1139) and fix whiteboard API encoding (#1155)#1162

Open
Ellien-Tang wants to merge 1 commit into
larksuite:mainfrom
Ellien-Tang:fix/1139-silent-exit-and-1155-encoding
Open

fix: prevent silent exits on error (#1139) and fix whiteboard API encoding (#1155)#1162
Ellien-Tang wants to merge 1 commit into
larksuite:mainfrom
Ellien-Tang:fix/1139-silent-exit-and-1155-encoding

Conversation

@Ellien-Tang
Copy link
Copy Markdown
Contributor

@Ellien-Tang Ellien-Tang commented May 28, 2026

This PR addresses two reported issues:

1. Fix silent exit with empty stderr (#1139)

When lark-cli fails in certain conditions (large --data payload, keychain session conflict), it exits with code 1 but produces absolutely no output — stdout and stderr are both empty. This makes it impossible to diagnose the root cause in automated/scripted contexts.

Changes:

  • main.go: Add panic recovery to print diagnostics to stderr instead of crashing silently (especially affects automation/CI contexts where a panic without stack trace looks like exit 1 with empty stdout/stderr).
  • cmd/root.go: Add defensive nil-checks in handleRootError() to guarantee a valid stderr writer even when Factory/IOStreams are unexpectedly nil.
  • internal/output/errors.go: WriteErrorEnvelope() now emits a minimal JSON envelope when ExitError.Detail is nil, preventing completely empty stderr.

2. Fix Chinese character encoding in whiteboard API (#1155)

When fetching whiteboard node data via API, Chinese characters in the JSON response display as garbled text (e.g. "高" shows as "Ú«ÿ").

Changes:

  • internal/client/encoding.go (new): Add autoDecodeBody() to detect and convert non-UTF-8 response bodies (GBK, GB18030, HZ-GB2312) that some Lark APIs return despite Content-Type claiming UTF-8.
  • internal/client/response.go: Integrate encoding auto-detection into ParseJSONResponse().

Fixes #1139
Fixes #1155

Summary by CodeRabbit

  • Bug Fixes
    • Improved error output handling during exceptional failures to prevent diagnostics from being lost
    • Added automatic encoding detection for response bodies, enabling support for international character sets
    • Enhanced error message reporting for legacy error types with missing details
    • Implemented panic recovery to gracefully handle and report unexpected runtime failures

Review Change Stack

@github-actions github-actions Bot added the size/L Large or sensitive change across domains or core paths label May 28, 2026
@CLAassistant
Copy link
Copy Markdown

CLA assistant check
Thank you for your submission! We really appreciate it. Like many open source projects, we ask that you sign our Contributor License Agreement before we can accept your contribution.


CLI Fix Bot seems not to be a GitHub user. You need a GitHub account to be able to sign the CLA. If you have already a GitHub account, please add the email address used for this commit to your account.
You have signed the CLA already but the status is still pending? Let us recheck it.

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 28, 2026

📝 Walkthrough

Walkthrough

The PR addresses silent failures in lark-cli by adding panic recovery, defensive error writer initialization, automatic response body encoding conversion for Chinese character sets, and error envelope fallbacks. These changes ensure diagnostics are always emitted to stderr, even in exceptional early-failure and encoding scenarios.

Changes

Silent Failure Prevention and Diagnostic Output

Layer / File(s) Summary
Process-level panic recovery and defensive error output
main.go, cmd/root.go
main() defers a panic recovery handler that prints panic value and stack trace to stderr; handleRootError now defensively selects f.IOStreams.ErrOut or falls back to os.Stderr when unavailable.
Response body encoding detection and normalization
internal/client/encoding.go, internal/client/response.go
New autoDecodeBody helper validates and normalizes UTF-8, strips BOM, and attempts decoding from Chinese encodings (GBK, GB18030, HZ-GB2312); ParseJSONResponse preprocesses bodies with this helper and uses the normalized result in error messages.
Error envelope output for legacy errors
internal/output/errors.go
WriteErrorEnvelope now handles legacy ExitError cases where Detail is nil by constructing a minimal JSON error payload instead of returning silently.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Poem

🐰 A rabbit's ode to silence broken:

No more shall panics pass unspoken,
Chinese characters decode with grace,
And errors find their rightful place—
In stderr streams, for all to see,
No silent exits—just clarity! 🌟

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title covers both major changes: preventing silent exits and fixing Chinese character encoding, clearly summarizing the two primary objectives.
Description check ✅ Passed The description provides comprehensive coverage of both issues, includes detailed changes, and links to related issues, though it lacks explicit test plan details.
Linked Issues check ✅ Passed All code changes align with linked issue objectives: panic recovery and nil-checks address #1139 silent exit problem; encoding.go and response.go changes address #1155 Chinese character encoding issue.
Out of Scope Changes check ✅ Passed All changes are directly scoped to the two linked issues; no extraneous modifications or refactoring unrelated to #1139 or #1155 are present.
Docstring Coverage ✅ Passed Docstring coverage is 80.00% which is sufficient. The required threshold is 80.00%.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@cmd/root.go`:
- Around line 217-225: In handleRootError, guard every dereference of f: compute
errOut as shown and then replace all direct uses of f.IOStreams.ErrOut with
errOut, and wrap any access to f (e.g., f.Name, f.CommandPath, or other fields)
in nil checks (if f != nil { ... } else { use sensible fallbacks or omit values)
so the function never dereferences f when it's nil; specifically update the code
paths that currently reference f at the later return/log/formatting sites to use
errOut and conditional checks around f before reading any of its fields.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 0723f875-f98f-468f-91ee-6a807e5d6993

📥 Commits

Reviewing files that changed from the base of the PR and between a2dde84 and c295b1c.

📒 Files selected for processing (5)
  • cmd/root.go
  • internal/client/encoding.go
  • internal/client/response.go
  • internal/output/errors.go
  • main.go

Comment thread cmd/root.go
Comment on lines +217 to +225
// Defensive: f or its IOStreams may be nil in exceptional situations
// (e.g. early bootstrap failure, plugin corruption). Guarantee stderr
// is always a valid writer so diagnostics are never swallowed.
var errOut io.Writer
if f != nil && f.IOStreams != nil && f.IOStreams.ErrOut != nil {
errOut = f.IOStreams.ErrOut
} else {
errOut = os.Stderr
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Guard all f dereferences in handleRootError to avoid nil panic paths.

The new fallback at Lines 217-225 is good, but f is still unconditionally dereferenced at Line 247 and Lines 256-259. If f is nil in the exceptional path this block targets, handleRootError can still panic.

Proposed fix
 func handleRootError(f *cmdutil.Factory, err error) int {
@@
 	var errOut io.Writer
 	if f != nil && f.IOStreams != nil && f.IOStreams.ErrOut != nil {
 		errOut = f.IOStreams.ErrOut
 	} else {
 		errOut = os.Stderr
 	}
+	identity := ""
+	if f != nil {
+		identity = string(f.ResolvedIdentity)
+	}
@@
-	applyNeedAuthorizationHint(f, err)
+	if f != nil {
+		applyNeedAuthorizationHint(f, err)
+	}
 
-	if output.WriteTypedErrorEnvelope(errOut, err, string(f.ResolvedIdentity)) {
+	if output.WriteTypedErrorEnvelope(errOut, err, identity) {
 		return output.ExitCodeOf(err)
 	}
@@
 	if exitErr := asExitError(err); exitErr != nil {
-		if !exitErr.Raw {
+		if !exitErr.Raw && f != nil {
 			// Raw errors (e.g. from `api` command via output.MarkRaw)
 			// preserve the original API error detail; skip enrichment
 			// which would clear it.
 			enrichMissingScopeError(f, exitErr)
 			enrichPermissionError(f, exitErr)
 		}
-		output.WriteErrorEnvelope(errOut, exitErr, string(f.ResolvedIdentity))
+		output.WriteErrorEnvelope(errOut, exitErr, identity)
 		return exitErr.Code
 	}

Also applies to: 245-247, 256-259

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@cmd/root.go` around lines 217 - 225, In handleRootError, guard every
dereference of f: compute errOut as shown and then replace all direct uses of
f.IOStreams.ErrOut with errOut, and wrap any access to f (e.g., f.Name,
f.CommandPath, or other fields) in nil checks (if f != nil { ... } else { use
sensible fallbacks or omit values) so the function never dereferences f when
it's nil; specifically update the code paths that currently reference f at the
later return/log/formatting sites to use errOut and conditional checks around f
before reading any of its fields.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size/L Large or sensitive change across domains or core paths

Projects

None yet

2 participants