{"record":{"id":"094c40fdd94c1f10","repo":"larksuite/cli","slug":"skill-reference-is-empty","errorCode":null,"errorMessage":"skill reference is empty","messagePattern":"skill reference is empty","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/skillref/ref.go","lineNumber":25,"sourceCode":"package skillref\n\nimport (\n\t\"fmt\"\n\t\"io/fs\"\n\t\"strings\"\n)\n\n// Ref is one exact canonical or runtime skill reference. Path is relative to\n// the named skill; an empty Path denotes the skill's SKILL.md.\ntype Ref struct {\n\tSkill string\n\tPath  string\n}\n\n// Parse parses the \"name[/relative/path]\" form accepted by `skills read`.\nfunc Parse(raw string) (Ref, error) {\n\tif raw == \"\" {\n\t\treturn Ref{}, fmt.Errorf(\"skill reference is empty\")\n\t}\n\tskill, path, _ := strings.Cut(raw, \"/\")\n\tif !ValidSkillName(skill) {\n\t\treturn Ref{}, fmt.Errorf(\"%q has invalid skill name %q\", raw, skill)\n\t}\n\tif path != \"\" && (!fs.ValidPath(path) || path == \".\" || strings.Contains(path, `\\`)) {\n\t\treturn Ref{}, fmt.Errorf(\"%q has invalid relative path %q\", raw, path)\n\t}\n\tif path == \"\" && strings.HasSuffix(raw, \"/\") {\n\t\treturn Ref{}, fmt.Errorf(\"%q has an empty relative path\", raw)\n\t}\n\treturn Ref{Skill: skill, Path: path}, nil\n}\n\n// ValidSkillName reports whether name can identify a top-level skill\n// directory. Keep this rule aligned with the skill-tree manifest validator.\nfunc ValidSkillName(name string) bool {\n\treturn name != \"\" && name != \".\" && name != \"..\" && !strings.ContainsAny(name, `/\\`)","sourceCodeStart":7,"sourceCodeEnd":43,"githubUrl":"https://github.com/larksuite/cli/blob/7fd6ef3c07182257ce776cdc5a614e122d5bd4b3/internal/skillref/ref.go#L7-L43","documentation":"skillref.Parse parses the \"name[/relative/path]\" reference form used by `skills read`. An empty input string has no skill component, so Parse immediately rejects it. Callers include remap validation in skillref.New and the skills read command path.","triggerScenarios":"Passing \"\" to skillref.Parse, or a Mapping whose From.String()/To.String() is empty (zero-value Ref) into skillref.New; an environment/flag variable holding the reference resolves to empty.","commonSituations":"An unset CLI flag or env var interpolated into a skill reference; constructing Ref{} with both fields empty and calling String(); scripts passing $UNSET_VAR directly to `skills read`.","solutions":["Provide a non-empty reference like \"auth\" or \"auth/TOKENS.md\".","Guard empty input before calling Parse: if raw == \"\" return early or default to a known skill.","Check why the flag/env is empty (typo in variable name, missing config entry) rather than bypassing validation.","For Mappings, ensure From and To are explicitly constructed, never the zero Ref{}."],"exampleFix":"// before\nref, err := skillref.Parse(os.Getenv(\"SKILL_REF\"))\n// after\nraw := os.Getenv(\"SKILL_REF\")\nif raw == \"\" {\n    return fmt.Errorf(\"SKILL_REF is not set\")\n}\nref, err := skillref.Parse(raw)","handlingStrategy":"validation","validationCode":"raw := os.Getenv(\"SKILL_REF\")\nif strings.TrimSpace(raw) == \"\" {\n    return errors.New(\"skill reference is required (e.g. auth or auth/TOKENS.md)\")\n}","typeGuard":null,"tryCatchPattern":"ref, err := skillref.Parse(raw)\nif err != nil {\n    return fmt.Errorf(\"--skill flag: %w\", err)\n}","preventionTips":["Check flags/env for emptiness before building skill references","Never pass a zero-value skillref.Ref through Mapping construction","Give CLI flags explicit required-value validation with usage examples"],"tags":["go","skillref","input-validation","empty-input"],"backgroundTag":"empty-skill-reference","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"}