git-ecosystem/git-credential-manager · error · Exception

Missing section header

Error message

Missing section header

What it means

IniFile.Deserialize parses .gitconfig-style INI content line by line; if a property line (key = value) appears before any [section] header has been seen, 'section' is still null and the parser throws "Missing section header". INI format requires properties to belong to a section, so a leading bare property is unrepresentable.

Solutions

  1. Open the config file and ensure every property appears under a [section] header — add the missing header at the top
  2. Check the exact line the parser failed on (it is the first property line before any section)
  3. Regenerate the config from a known-good template rather than hand-editing
  4. If constructing INI text programmatically, always emit "[section]\n" before any key=value pairs

Example fix

// before (file content)
// name = value
//
// after
// [user]
// name = value
Defensive patterns

Strategy: try-catch

Validate before calling

var text = File.ReadAllText(path);
var firstNonEmpty = text.Split('\n').FirstOrDefault(l => !string.IsNullOrWhiteSpace(l)) ?? "";
if (!firstNonEmpty.TrimStart().StartsWith("["))
    throw new InvalidDataException($"{path}: first content line must be a [section] header");

Type guard

bool HasSectionHeader(string iniText) => iniText
    .Split('\n')
    .Any(l => l.TrimStart().StartsWith("[")) &&
    !string.IsNullOrWhiteSpace(iniText.Split('\n').FirstOrDefault(l => !string.IsNullOrWhiteSpace(l))) &&
    iniText.Split('\n').First(l => !string.IsNullOrWhiteSpace(l)).TrimStart().StartsWith("[");

Try / catch

try
{
    var ini = IniFile.Deserialize(path, fileSystem);
}
catch (Exception ex) when (ex.Message == "Missing section header")
{
    logger.LogError(ex, "{Path} is malformed: a key=value appears before any [section] header", path);
}

Prevention

When it happens

Trigger: Deserializing config text/file where a property line occurs before the first [section] line — e.g. a file starting with "name = value", corrupted config missing its first header, or a truncated file.

Common situations: Hand-edited or machine-generated .gitconfig files missing the initial [core]/[user] header, config files concatenated incorrectly, or templates where the section header line was deleted.

Understand the failure class

Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.


AI-assisted analysis of git-ecosystem/git-credential-manager@e8ce762cd0 (2026-09-11). Data as JSON: /api/errors/69027456db9cbd3a. Report an issue: GitHub.

Appendix: source

Thrown at src/Core/IniFile.cs:171

                        continue;
                    }

                    if (!iniFile.TryGetSection(mainName, subName, out section))
                    {
                        var sectionName = new IniSectionName(mainName, subName);
                        section = new IniSection(sectionName);
                        iniFile.Sections[sectionName] = section;
                    }

                    continue;
                }

                match = PropertyRegex.Match(line);
                if (match.Success)
                {
                    if (section is null)
                    {
                        throw new Exception("Missing section header");
                    }

                    string propName = match.Groups["name"].Value;
                    string propValue = match.Groups["value"].Value.Trim();

                    // Trim trailing comments
                    int firstDQuote = propValue.IndexOf('"');
                    int lastDQuote = propValue.LastIndexOf('"');
                    int commentIdx = propValue.LastIndexOf('#');
                    if (commentIdx > -1)
                    {
                        bool insideDQuotes = firstDQuote > -1 && lastDQuote > -1 &&
                                             (firstDQuote < commentIdx && commentIdx < lastDQuote);

                        if (!insideDQuotes)
                        {
                            propValue = propValue.Substring(0, commentIdx).Trim();
                        }

View on GitHub (pinned to e8ce762cd0)