{"record":{"id":"4a0582efa23c88e1","repo":"larksuite/cli","slug":"pass-exactly-one-of-url-or-spreadsheet-token","errorCode":null,"errorMessage":"Pass exactly one of --url or --spreadsheet-token","messagePattern":"Pass exactly one of --url or --spreadsheet-token","errorType":"validation","errorClass":"LarkCliError","httpStatus":null,"severity":"error","filePath":"skills/lark-sheets/scripts/lark_sheet_read_cli.py","lineNumber":55,"sourceCode":"        return\n    if isinstance(value, bool):\n        cmd.append(flag if value else f\"{flag}=false\")\n        return\n    cmd.extend([flag, str(value)])\n\n\ndef run_sheets(\n    shortcut: str,\n    *,\n    url: str | None = None,\n    spreadsheet_token: str | None = None,\n    sheet_id: str | None = None,\n    sheet_name: str | None = None,\n    flags: dict[str, Any] | None = None,\n    timeout: int = 60,\n) -> dict[str, Any]:\n    if bool(url) == bool(spreadsheet_token):\n        raise LarkCliError(\"Pass exactly one of --url or --spreadsheet-token\")\n    if sheet_id and sheet_name:\n        raise LarkCliError(\"Pass only one of --sheet-id or --sheet-name\")\n\n    cmd = [\"lark-cli\", \"sheets\", shortcut]\n    _append_flag(cmd, \"url\", url)\n    _append_flag(cmd, \"spreadsheet_token\", spreadsheet_token)\n    _append_flag(cmd, \"sheet_id\", sheet_id)\n    _append_flag(cmd, \"sheet_name\", sheet_name)\n    for key, value in (flags or {}).items():\n        _append_flag(cmd, key, value)\n\n    try:\n        completed = subprocess.run(\n            cmd,\n            capture_output=True,\n            text=True,\n            timeout=timeout,\n            check=False,","sourceCodeStart":37,"sourceCodeEnd":73,"githubUrl":"https://github.com/larksuite/cli/blob/7fd6ef3c07182257ce776cdc5a614e122d5bd4b3/skills/lark-sheets/scripts/lark_sheet_read_cli.py#L37-L73","documentation":"run_sheets() in lark_sheet_read_cli.py requires the caller to identify the spreadsheet in exactly one way: either a --url or a --spreadsheet-token. It checks `bool(url) == bool(spreadsheet_token)`, so providing both, or neither, is rejected with LarkCliError before the lark-cli subprocess is invoked.","triggerScenarios":"Calling run_sheets()/read helpers with both url and spreadsheet_token set, or with both None/empty (e.g. forgetting to pass the URL entirely).","commonSituations":"Config files or CLI parsing that fill in a default token while a URL is also passed; copying an example that sets url but leaving a stale spreadsheet_token in config; omitting both because the script expected an environment variable to provide one.","solutions":["Pass exactly one identifier: delete the spreadsheet_token argument if you pass url, and vice versa.","If both are populated, extract the token from the URL (the token is the spreadsheet ID segment) and pass only that.","If neither is set, resolve the URL/token from config, env, or the command line before calling run_sheets."],"exampleFix":"// before\nrun_sheets(\"read\", url=sheet_url, spreadsheet_token=token)  # LarkCliError\n\n// after\nrun_sheets(\"read\", url=sheet_url)  # exactly one identifier","handlingStrategy":"validation","validationCode":"if bool(url) == bool(spreadsheet_token):\n    raise SystemExit(\"Provide exactly one of --url or --spreadsheet-token\")","typeGuard":"def has_one_identifier(url, token) -> bool:\n    return bool(url) != bool(token)","tryCatchPattern":"try:\n    data = run_sheets(shortcut, url=url, spreadsheet_token=token)\nexcept LarkCliError as e:\n    if \"exactly one of --url or --spreadsheet-token\" in str(e):\n        data = run_sheets(shortcut, url=url or f\"https://example.feishu.cn/sheets/{token}\")\n    else:\n        raise","preventionTips":["Normalize input early: derive the token from the URL once, then only pass one form.","In CLI wrappers, make --url and --spreadsheet-token a mutually exclusive group.","Never bake a default token into config that can coexist with a user-supplied URL."],"tags":["python","cli","argument-validation","mutually-exclusive"],"backgroundTag":"conflicting-arguments","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"}