{"record":{"id":"79c360cc1b813bf0","repo":"hashicorp/nomad","slug":"failed-to-parse-df-output-expected-at-least-2-l","errorCode":null,"errorMessage":"failed to parse `df` output; expected at least 2 lines","messagePattern":"failed to parse `df` output; expected at least 2 lines","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"client/fingerprint/storage_unix.go","lineNumber":44,"sourceCode":"\tvar dfArgs string\n\tif runtime.GOOS == \"linux\" {\n\t\t// df on linux needs the -P option to prevent linebreaks on long filesystem paths\n\t\tdfArgs = \"-kP\"\n\t} else {\n\t\tdfArgs = \"-k\"\n\t}\n\n\tmountOutput, err := exec.Command(\"df\", dfArgs, absPath).Output()\n\tif err != nil {\n\t\treturn \"\", 0, fmt.Errorf(\"failed to determine mount point for %s\", absPath)\n\t}\n\t// Output looks something like:\n\t//\tFilesystem 1024-blocks      Used Available Capacity   iused    ifree %iused  Mounted on\n\t//\t/dev/disk1   487385240 423722532  63406708    87% 105994631 15851677   87%   /\n\t//\t[0] volume [1] capacity [2] SKIP  [3] free\n\tlines := strings.Split(string(mountOutput), \"\\n\")\n\tif len(lines) < 2 {\n\t\treturn \"\", 0, fmt.Errorf(\"failed to parse `df` output; expected at least 2 lines\")\n\t}\n\tfields := strings.Fields(lines[1])\n\tif len(fields) < 4 {\n\t\treturn \"\", 0, fmt.Errorf(\"failed to parse `df` output; expected at least 4 columns\")\n\t}\n\tvolume = fields[0]\n\n\ttotal, err = strconv.ParseUint(fields[1], 10, 64)\n\tif err != nil {\n\t\treturn \"\", 0, fmt.Errorf(\"failed to parse storage.bytestotal size in kilobytes\")\n\t}\n\t// convert to bytes\n\ttotal *= 1024\n\n\treturn volume, total, nil\n}\n","sourceCodeStart":26,"sourceCodeEnd":61,"githubUrl":"https://github.com/hashicorp/nomad/blob/482b49bf1aec006f089bcfc7e632d8f6ac303e5e/client/fingerprint/storage_unix.go#L26-L61","documentation":"In StorageFingerprint.diskInfo, the output of running `df -kP <path>` has fewer than 2 lines, meaning the df invocation returned output in an unexpected format (or the mount point lookup failed earlier), so volume name and free bytes cannot be extracted for the storage fingerprint.","triggerScenarios":"df output for absPath contains fewer than 2 newline-separated lines — e.g. df emitted only an error/usage line to stdout or no data row for the path.","commonSituations":"Non-standard df implementations (BusyBox variants, exotic platforms) with unexpected output; df writing diagnostics instead of a table; locale/behavior differences after OS upgrades.","solutions":["Verify `df -k <path>` manually prints a header plus one data row.","Use a standard df (GNU coreutils / BSD) rather than a minimal replacement.","Pin the platform image to one with known-good coreutils.","Provide DiskTotalMB override to bypass df parsing."],"exampleFix":"// before\nPATH=\"$CUSTOM_BIN:$PATH\" df ...  # nonstandard df\n// after\napt-get install -y coreutils  # standard df on PATH","handlingStrategy":"validation","validationCode":"out, err := exec.Command(\"df\", \"-k\", path).Output()\nif err != nil || len(strings.Split(string(out), \"\\n\")) < 2 {\n\treturn fmt.Errorf(\"df output not parseable for %s; check df implementation\", path)\n}","typeGuard":null,"tryCatchPattern":"if err := fp.Fingerprint(req); err != nil {\n\tif strings.Contains(err.Error(), \"expected at least 2 lines\") {\n\t\tlog.Printf(\"df output shape unexpected: %v\", err)\n\t\treturn nil\n\t}\n\treturn err\n}","preventionTips":["Use a standard df implementation (GNU coreutils / BSD).","Test df output on the target platform before deploying.","Avoid df wrapper scripts that change output shape.","Set DiskTotalMB override on platforms with nonstandard df."],"tags":["filesystem","df","parsing","fingerprinting"],"backgroundTag":"df-output-parse-failed","analyzedSha":"482b49bf1aec006f089bcfc7e632d8f6ac303e5e","analyzedAt":"2026-09-04T07:54:14.808Z","contentChangedAt":"2026-09-04T07:54:14.808Z","schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}