{"record":{"id":"a5be3660307a41e6","repo":"jdx/mise","slug":"unterminated-use-block","errorCode":null,"errorMessage":"unterminated use block","messagePattern":"unterminated use block","errorType":"validation","errorClass":"eyre::Report","httpStatus":null,"severity":"error","filePath":"src/task/workspace/go.rs","lineNumber":145,"sourceCode":"                format!(\"invalid use directive on line {line_number}\")\n            })?));\n            continue;\n        }\n\n        let Some(arguments) = directive_arguments(line, \"use\") else {\n            continue;\n        };\n        if arguments == \"(\" {\n            in_use_block = true;\n        } else {\n            directories.push(PathBuf::from(parse_argument(arguments).wrap_err_with(\n                || format!(\"invalid use directive on line {line_number}\"),\n            )?));\n        }\n    }\n\n    if in_use_block {\n        bail!(\"unterminated use block\");\n    }\n    Ok(directories)\n}\n\nfn read_module_path(context: &WorkspaceDiscoveryContext, path: &Path) -> Result<String> {\n    let contents = context\n        .read_to_string(path)\n        .wrap_err_with(|| format!(\"failed to read Go module metadata {}\", path.display()))?;\n    let mut module_path = None;\n\n    for (index, raw_line) in contents.lines().enumerate() {\n        let line = strip_comment(raw_line).trim();\n        let Some(arguments) = directive_arguments(line, \"module\") else {\n            continue;\n        };\n        let parsed = parse_argument(arguments)\n            .wrap_err_with(|| format!(\"invalid module directive on line {}\", index + 1))?;\n        if module_path.replace(parsed).is_some() {","sourceCodeStart":127,"sourceCodeEnd":163,"githubUrl":"https://github.com/jdx/mise/blob/6f52dcdf99e282ef7a7db68c81301fa4618d0f79/src/task/workspace/go.rs#L127-L163","documentation":"parse_workfile tracks multi-line `use (` blocks in go.work and requires them to be closed by a line that is exactly \")\" before end of file; an unclosed block leaves the parser in block state at EOF and this error aborts Go workspace discovery. Single-line `use ./dir` entries are unaffected.","triggerScenarios":"A go.work whose `use (` block is missing the closing \")\"; a truncated file (last line lost in an edit or failed write); a merge conflict resolution that dropped the closing paren; a commented-out `)` line (// ) is stripped by strip_comment and no longer closes the block).","commonSituations":"Hand-editing go.work instead of using `go work edit`; git merge conflicts in go.work; copy-pasting a block and missing the tail; tooling that appends entries without preserving the closer.","solutions":["Add the closing \")\" on its own line at the end of the use block","Prefer `go work use ./dir` or `go work edit -use ./dir` so the toolchain keeps the file well-formed","Validate with `go work sync` — the go toolchain itself rejects an unterminated block, catching it before mise runs"],"exampleFix":"# before (go.work)\nuse (\n    ./api\n    ./worker\n\n# after\nuse (\n    ./api\n    ./worker\n)","handlingStrategy":"validation","validationCode":"fn use_blocks_closed(contents: &str) -> bool {\n    let mut depth_open = false;\n    for raw in contents.lines() {\n        let line = raw.split(\"//\").next().unwrap_or(\"\").trim();\n        if line == \"use (\" { depth_open = true; }\n        else if line == \")\" && depth_open { depth_open = false; }\n    }\n    !depth_open\n}","typeGuard":"fn is_balanced_go_work(contents: &str) -> bool {\n    let mut in_block = false;\n    for raw in contents.lines() {\n        let line = raw.split(\"//\").next().unwrap_or(\"\").trim();\n        match line.as_str() {\n            \"use (\" => in_block = true,\n            \")\" if in_block => in_block = false,\n            _ => {}\n        }\n    }\n    !in_block\n}","tryCatchPattern":"Err(report) if report.to_string().contains(\"unterminated use block\") => {\n    // append the missing closer and retry once, then fail loudly if it recurs\n    contents.push_str(\"\\n)\\n\");\n    retry_parse(&contents)?;\n}","preventionTips":["Edit go.work through `go work use` / `go work edit` instead of by hand","Check that a lone \")\" closer survived merge-conflict resolution (a commented `// )` no longer closes the block)","Run `go work sync` before committing go.work changes"],"tags":["go","workspace","go-work","parse","syntax"],"backgroundTag":"unbalanced-delimiters","analyzedSha":"6f52dcdf99e282ef7a7db68c81301fa4618d0f79","analyzedAt":"2026-08-22T10:14:23.840Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T15:18:49.778Z"}