{"record":{"id":"5b8935eb6d66c964","repo":"jdx/mise","slug":"invalid-lockfile-format-for-tool-short-expected","errorCode":null,"errorMessage":"invalid lockfile format for tool {short}: expected array ([[tools.{short}]])","messagePattern":"invalid lockfile format for tool (.+?): expected array \\(\\[\\[tools\\.(.+?)\\]\\]\\)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/lockfile.rs","lineNumber":1220,"sourceCode":"\n        let tools: toml::Table = table\n            .remove(\"tools\")\n            .unwrap_or(toml::Table::new().into())\n            .try_into()?;\n\n        let mut lockfile = Lockfile {\n            lockfile_version,\n            generated_header_url,\n            ..Default::default()\n        };\n\n        for (short, value) in tools {\n            let versions = match value {\n                toml::Value::Array(arr) => arr\n                    .into_iter()\n                    .map(LockfileTool::try_from)\n                    .collect::<Result<Vec<_>>>()?,\n                _ => bail!(\n                    \"invalid lockfile format for tool {short}: expected array ([[tools.{short}]])\"\n                ),\n            };\n            let versions = versions\n                .into_iter()\n                .map(|mut entry| -> Result<_> {\n                    if let Some(graph) = &mut entry.uv {\n                        graph.resolve_path(path)?;\n                    }\n                    if let Some(graph) = &mut entry.aube {\n                        graph.resolve_path(path)?;\n                    }\n                    Ok(entry)\n                })\n                .collect::<Result<Vec<_>>>()?;\n            lockfile.tools.entry(short).or_default().extend(versions);\n        }\n","sourceCodeStart":1202,"sourceCodeEnd":1238,"githubUrl":"https://github.com/jdx/mise/blob/533346cc374382b41ec5ff70536252b2e96e725c/src/lockfile.rs#L1202-L1238","documentation":"In mise.lock the `tools` section must map each tool shorthand to an array of version entries, i.e. TOML written as `[[tools.<short>]]` repeated per version. If the value for a tool is any other TOML type (a plain table, string, etc.), the parser bails with this message naming the offending tool.","triggerScenarios":"Parsing a mise.lock where `tools.<name>` is not an array — e.g. someone wrote `[tools.node]` (single table) instead of `[[tools.node]]`, or merged versions into an inline table.","commonSituations":"Hand-authoring or hand-editing lockfile tool entries; merge conflicts resolved into a single table; scripts generating lockfiles with the wrong TOML syntax (single vs double brackets).","solutions":["Fix the TOML in mise.lock: use double-bracket array-of-tables syntax, one [[tools.<short>]] block per version.","Remove the malformed tool entry and re-run `mise lock` to regenerate it.","Restore mise.lock from version control if a merge broke the structure."],"exampleFix":"# before (mise.lock)\n[tools.node]\nversion = \"22\"\n\n# after\n[[tools.node]]\nversion = \"22\"","handlingStrategy":"validation","validationCode":"const tools = doc.get('tools');\nfor (const [name, v] of Object.entries(tools || {})) {\n  if (!Array.isArray(v)) throw new Error(`tools.${name} must be an array of tables ([[tools.${name}]])`);\n}","typeGuard":"function isArrayOfTables(v) { return Array.isArray(v) && v.every(x => typeof x === 'object' && x !== null); }","tryCatchPattern":null,"preventionTips":["Use [[tools.<name>]] (double brackets) per version when authoring TOML.","Never resolve lockfile merge conflicts by collapsing entries into one table.","Prefer regenerating the lockfile over hand-editing tool entries."],"tags":["lockfile","parsing","toml","config"],"backgroundTag":"invalid-argument-format","analyzedSha":"533346cc374382b41ec5ff70536252b2e96e725c","analyzedAt":"2026-09-17T13:35:38.149Z","contentChangedAt":"2026-09-17T13:35:38.149Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}