{"record":{"id":"3eb4a0a0d109544e","repo":"larksuite/cli","slug":"json-dumps-envelope-ensure-ascii-false","errorCode":null,"errorMessage":"{json.dumps(envelope, ensure_ascii=False)}","messagePattern":"\\{json\\.dumps\\(envelope, ensure_ascii=False\\)\\}","errorType":"exception","errorClass":"LarkCliError","httpStatus":null,"severity":"error","filePath":"skills/lark-sheets/scripts/lark_sheet_read_cli.py","lineNumber":91,"sourceCode":"            check=False,\n        )\n    except FileNotFoundError as exc:\n        raise LarkCliError(\"lark-cli not found\", cmd=cmd) from exc\n    except subprocess.TimeoutExpired as exc:\n        raise LarkCliError(f\"lark-cli timed out after {timeout}s\", cmd=cmd) from exc\n\n    if completed.returncode != 0:\n        detail = (completed.stderr or completed.stdout or \"\").strip()\n        raise LarkCliError(detail or f\"lark-cli exited with {completed.returncode}\", cmd=cmd)\n\n    try:\n        envelope = json.loads(completed.stdout)\n    except json.JSONDecodeError as exc:\n        snippet = completed.stdout[:500].replace(\"\\n\", \"\\\\n\")\n        raise LarkCliError(f\"lark-cli stdout was not JSON: {snippet}\", cmd=cmd) from exc\n\n    if isinstance(envelope, dict) and envelope.get(\"ok\") is False:\n        raise LarkCliError(json.dumps(envelope, ensure_ascii=False), cmd=cmd)\n    if not isinstance(envelope, dict):\n        raise LarkCliError(\"lark-cli returned a non-object JSON payload\", cmd=cmd)\n    return envelope\n\n\ndef envelope_data(envelope: dict[str, Any]) -> dict[str, Any]:\n    data = envelope.get(\"data\")\n    return data if isinstance(data, dict) else envelope\n\n\ndef emit_success(action: str, data: dict[str, Any], warnings: list[str] | None = None) -> None:\n    print(\n        json.dumps(\n            {\n                \"ok\": True,\n                \"engine\": \"lark\",\n                \"action\": action,\n                \"data\": data,","sourceCodeStart":73,"sourceCodeEnd":109,"githubUrl":"https://github.com/larksuite/cli/blob/7fd6ef3c07182257ce776cdc5a614e122d5bd4b3/skills/lark-sheets/scripts/lark_sheet_read_cli.py#L73-L109","documentation":"When lark-cli exits 0 and returns valid JSON but the envelope has `\"ok\": false`, run_sheets() raises LarkCliError with the full envelope serialized as the message. This is the wrapper's normal path for surfacing a Lark API or command-level failure: the CLI handled the request but the operation itself failed, and the complete error envelope (often including code, msg, and fields like missing_scopes or log_id) is preserved verbatim in the message for the caller to inspect.","triggerScenarios":"Any run_sheets() call where the lark-cli response parses to a dict with envelope.get(\"ok\") is False — e.g. invalid spreadsheet token/URL, no access to the sheet, expired or missing auth token, insufficient scopes, nonexistent sheet_id, or a Lark API error code returned by the backend.","commonSituations":"Stale/expired lark-cli login credentials; the bot or user lacks permission on the spreadsheet; typo'd --spreadsheet-token or --url; sheet renamed or deleted so --sheet-name no longer matches; tenant admin hasn't granted required scopes; rate limiting from the Lark API.","solutions":["Parse the JSON in the error message (it is a complete envelope) and read its `error`/`code`/`msg` fields to identify the exact failure.","Re-authenticate: run `lark-cli auth login` (or equivalent) if the envelope indicates token/credential problems.","Check missing_scopes or permission fields in the envelope; grant the required scopes to the app/user in the Lark admin console.","Verify the --spreadsheet-token/--url and --sheet-id/--sheet-name values against the actual spreadsheet.","Retry with backoff if the envelope indicates a transient/rate-limit error code."],"exampleFix":"# before: treating any LarkCliError the same\ntry:\n    env = run_sheets(\"read\", spreadsheet_token=token, sheet_id=sid)\nexcept LarkCliError as exc:\n    raise\n# after: decode the embedded envelope and react to the API error code\ntry:\n    env = run_sheets(\"read\", spreadsheet_token=token, sheet_id=sid)\nexcept LarkCliError as exc:\n    envelope = json.loads(str(exc))\n    if envelope.get(\"code\") == 99991663:  # token invalid/expired\n        reauthenticate()\n    raise","handlingStrategy":"try-catch","validationCode":"# confirm credentials and target access before calling the API\nimport subprocess\nwho = subprocess.run([\"lark-cli\", \"auth\", \"whoami\"], capture_output=True, text=True)\nif who.returncode != 0:\n    raise RuntimeError(\"not authenticated: run `lark-cli auth login` first\")","typeGuard":"import json\ndef is_failure_envelope(message: str) -> dict | None:\n    try:\n        env = json.loads(message)\n    except json.JSONDecodeError:\n        return None\n    return env if isinstance(env, dict) and env.get(\"ok\") is False else None","tryCatchPattern":"import json\nfrom lark_sheet_read_cli import LarkCliError\ntry:\n    envelope = run_sheets(\"read\", spreadsheet_token=token, sheet_id=sid)\nexcept LarkCliError as exc:\n    env = json.loads(str(exc))  # message is the full failure envelope\n    code = env.get(\"code\")\n    if code == 99991663:\n        reauthenticate()\n    elif env.get(\"missing_scopes\"):\n        print(\"grant scopes:\", env[\"missing_scopes\"])\n    raise","preventionTips":["Refresh lark-cli auth before long-running automations.","Verify the bot/user has permission on the target spreadsheet and required scopes are granted.","Validate --spreadsheet-token/--url/--sheet-id values before invoking.","Handle rate-limit codes with exponential backoff instead of tight retries."],"tags":["api-error","envelope","cli","lark"],"backgroundTag":"api-error-envelope","analyzedSha":"7fd6ef3c07182257ce776cdc5a614e122d5bd4b3","analyzedAt":"2026-09-04T21:17:44.649Z","contentChangedAt":"2026-09-04T21:17:44.649Z","schemaVersion":2},"datasetVersion":"2026-09-12T02:17:10.037Z"}