{"record":{"id":"2236b4ec56a1627a","repo":"larksuite/cli","slug":"anchor-outside-sheet-position-r","errorCode":null,"errorMessage":"anchor outside sheet: {position!r}","messagePattern":"anchor outside sheet: (.+?)","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"skills/lark-sheets/scripts/lark_chart_layout_check.py","lineNumber":159,"sourceCode":"            if sheet_identifier(sheet) == sheet_id or sheet_title(sheet) == title:\n                charts = sheet.get(\"charts\")\n                return [chart for chart in charts if isinstance(chart, dict)] if isinstance(charts, list) else []\n    charts = data.get(\"charts\")\n    return [chart for chart in charts if isinstance(chart, dict)] if isinstance(charts, list) else []\n\n\ndef chart_rectangle(\n    chart: dict[str, Any], row_edges: list[float], column_edges: list[float]\n) -> dict[str, Any]:\n    details = chart.get(\"details\") if isinstance(chart.get(\"details\"), dict) else chart\n    position = details.get(\"position\") if isinstance(details.get(\"position\"), dict) else {}\n    offset = details.get(\"offset\") if isinstance(details.get(\"offset\"), dict) else {}\n    size = details.get(\"size\") if isinstance(details.get(\"size\"), dict) else {}\n\n    row = int(position[\"row\"])\n    column = column_to_index(str(position[\"col\"]))\n    if row < 0 or column < 0 or row >= len(row_edges) - 1 or column >= len(column_edges) - 1:\n        raise ValueError(f\"anchor outside sheet: {position!r}\")\n\n    width = float(size[\"width\"])\n    height = float(size[\"height\"])\n    if width <= 0 or height <= 0:\n        raise ValueError(f\"invalid chart size: {size!r}\")\n\n    left = column_edges[column] + float(offset.get(\"col_offset\", 0) or 0)\n    top = row_edges[row] + float(offset.get(\"row_offset\", 0) or 0)\n    return {\n        \"chart_id\": str(chart.get(\"chart_id\") or chart.get(\"id\") or \"\"),\n        \"anchor_cell\": f\"{index_to_column(column)}{row + 1}\",\n        \"left\": left,\n        \"top\": top,\n        \"right\": left + width,\n        \"bottom\": top + height,\n        \"width\": width,\n        \"height\": height,\n    }","sourceCodeStart":141,"sourceCodeEnd":177,"githubUrl":"https://github.com/larksuite/cli/blob/7fd6ef3c07182257ce776cdc5a614e122d5bd4b3/skills/lark-sheets/scripts/lark_chart_layout_check.py#L141-L177","documentation":"A whole-skill remap (source Ref without a Path) must map to a bare target skill (Ref without a Path). skillref.New rejects mixing granularities because a whole-skill rename cannot project to a single exact file reference for every path under the skill.","triggerScenarios":"Calling skillref.New with a Mapping whose From.Path == \"\" but whose To has a non-empty Path (e.g. remap skill 'auth' -> 'skills/auth/login.md').","commonSituations":"Confusing whole-skill rename entries with exact-reference override entries when editing overlay configs; a tool that rewrites one entry type into the other without normalizing the target.","solutions":["Make the target a bare skill reference (no path) to rename the whole skill, e.g. auth -> new-auth.","If you actually want an exact-reference override, give the source a path too (e.g. auth/login.md -> new-skill/login.md) so both sides are exact.","Split the intent: one whole-skill rename entry plus separate exact overrides if only some paths should differ."],"exampleFix":"// before\n{From: skillref.Ref{Skill: \"auth\"}, To: skillref.Ref{Skill: \"auth-v2\", Path: \"login.md\"}}\n// after\n{From: skillref.Ref{Skill: \"auth\"}, To: skillref.Ref{Skill: \"auth-v2\"}}","handlingStrategy":"validation","validationCode":"func validateGranularity(m skillref.Mapping) error {\n    if m.From.Path == \"\" && m.To.Path != \"\" {\n        return fmt.Errorf(\"whole-skill remap %q needs a bare target, got %q\", m.From.String(), m.To.String())\n    }\n    return nil\n}","typeGuard":"func isWholeSkillRef(r skillref.Ref) bool { return r.Path == \"\" }","tryCatchPattern":null,"preventionTips":["Keep whole-skill renames and exact overrides as clearly separated config sections.","Validate mapping granularity before constructing the Resolver.","Document that a pathless source requires a pathless target."],"tags":["go","validation","config","skill-reference"],"backgroundTag":"invalid-skill-reference-mapping","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"}