{"record":{"id":"ba994ffbdd003058","repo":"xai-org/grok-build","slug":"no-version-field-in-plugin-json-set-a-version-t","errorCode":null,"errorMessage":"No `version` field in plugin.json. Set a version to use `grok plugin tag`.","messagePattern":"No `version` field in plugin\\.json\\. Set a version to use `grok plugin tag`\\.","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/codegen/xai-grok-pager/src/plugin_cmd.rs","lineNumber":720,"sourceCode":"            println!(\n                \"No plugin.json found. Grok discovers skills, agents, and hooks \\\n                 automatically from standard directories. A manifest is only needed \\\n                 for custom paths or metadata.\"\n            );\n            Ok(())\n        }\n        Err(e) => bail!(\"Failed to load manifest: {e}\"),\n    }\n}\n\nfn cmd_tag(path: &str, push: bool, force: bool, dry_run: bool) -> Result<()> {\n    let root = PathBuf::from(path);\n    if !root.is_dir() {\n        bail!(\"Not a directory: {path}\");\n    }\n    let version = match load_manifest(&root) {\n        Ok(ManifestLoadResult::Found(m)) => m.version.ok_or_else(|| {\n            anyhow::anyhow!(\n                \"No `version` field in plugin.json. Set a version to use `grok plugin tag`.\"\n            )\n        })?,\n        Ok(ManifestLoadResult::NotFound) => bail!(\"No plugin.json found in {path}.\"),\n        Err(e) => bail!(\"Failed to load manifest: {e}\"),\n    };\n\n    let tag = format!(\n        \"v{}\",\n        version\n            .strip_prefix('v')\n            .or_else(|| version.strip_prefix('V'))\n            .unwrap_or(&version)\n    );\n\n    if !force {\n        let out = std::process::Command::new(\"git\")\n            .args([\"status\", \"--porcelain\"])","sourceCodeStart":702,"sourceCodeEnd":738,"githubUrl":"https://github.com/xai-org/grok-build/blob/bc7f02eddd3d84085849dc19ed216f11c23b0571/crates/codegen/xai-grok-pager/src/plugin_cmd.rs#L702-L738","documentation":"`grok plugin tag` derives a git tag from the manifest version, but the loaded plugin.json has no `version` field (`m.version` is None). The command refuses to tag without a version and tells the user to add one.","triggerScenarios":"Running `grok plugin tag <path>` on a plugin whose plugin.json omits `version` (or has it only under an unrecognized key), so `load_manifest` yields Found with `version: None`.","commonSituations":"Minimal plugin manifests that skip versioning; manifest hand-written without version; version accidentally removed during a refactor.","solutions":["Add a `\"version\": \"x.y.z\"` field to plugin.json in the plugin root","Re-run `grok plugin tag <path>`","If version lives elsewhere (e.g. Cargo.toml), mirror it into plugin.json since tagging only reads the manifest"],"exampleFix":"// before (plugin.json)\n{ \"name\": \"my-plugin\" }\n// after\n{ \"name\": \"my-plugin\", \"version\": \"0.1.0\" }","handlingStrategy":"validation","validationCode":"let m: serde_json::Value = serde_json::from_str(&std::fs::read_to_string(\"plugin.json\")?)?;\nif m.get(\"version\").and_then(|v| v.as_str()).is_none() {\n    eprintln!(\"plugin.json needs a \\\"version\\\" field before grok plugin tag\");\n}","typeGuard":null,"tryCatchPattern":"match manifest.version {\n    Some(v) => tag_with(v),\n    None => eprintln!(\"add \\\"version\\\": \\\"x.y.z\\\" to plugin.json to use grok plugin tag\"),\n}","preventionTips":["Always include name+version+description in plugin.json scaffolds","Keep plugin.json version in sync with Cargo.toml/package version","Add a CI check that manifest version is present and semver"],"tags":["manifest","versioning","plugin"],"backgroundTag":"missing-manifest-field","analyzedSha":"bc7f02eddd3d84085849dc19ed216f11c23b0571","analyzedAt":"2026-08-31T04:59:42.031Z","schemaVersion":2},"datasetVersion":"2026-08-31T09:17:48.483Z"}