{"record":{"id":"e7508cfdbb5c92c5","repo":"dagger/dagger","slug":"lockfile-line-d-w","errorCode":null,"errorMessage":"lockfile line %d: %w","messagePattern":"lockfile line (.+?): %w","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"util/lockfile/lockfile.go","lineNumber":80,"sourceCode":"// Lines starting with \"#\" are comments and are ignored. Non-empty files must\n// otherwise start with a supported version header line.\nfunc Parse(data []byte) (*Lockfile, error) {\n\tlock := New()\n\tlines := bytes.Split(data, []byte(\"\\n\"))\n\n\tfirstContentLine := true\n\tversion := \"\"\n\tfor i, rawLine := range lines {\n\t\tline := strings.TrimSpace(string(rawLine))\n\t\tif line == \"\" || strings.HasPrefix(line, commentPrefix) {\n\t\t\tcontinue\n\t\t}\n\n\t\tif firstContentLine {\n\t\t\tvar err error\n\t\t\tversion, err = parseVersionHeader([]byte(line))\n\t\t\tif err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"lockfile line %d: %w\", i+1, err)\n\t\t\t}\n\t\t\tfirstContentLine = false\n\t\t\tcontinue\n\t\t}\n\n\t\tentry, err := parseEntry([]byte(line), version)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"lockfile line %d: %w\", i+1, err)\n\t\t}\n\t\tlock.entries[entryKey(entry.namespace, entry.operation, entry.inputsJSON)] = entry\n\t}\n\n\treturn lock, nil\n}\n\n// Marshal encodes lockfile entries to deterministic JSON lines, preceded by\n// HeaderComment and the version header. Comments present in the parsed input\n// are not preserved.","sourceCodeStart":62,"sourceCodeEnd":98,"githubUrl":"https://github.com/dagger/dagger/blob/82ba2681dbe30d3547a1dc50ea495900ab5b6047/util/lockfile/lockfile.go#L62-L98","documentation":"lockfile.Parse requires the first non-empty, non-comment line to be a valid version header (a JSON array like [[\"version\",\"2\"]]). If parseVersionHeader fails — invalid JSON, missing header, wrong shape, or an unsupported version — the error is wrapped with the 1-based line number.","triggerScenarios":"Calling Parse on bytes whose first content line is not [[\"version\",\"2\"]] — e.g. a random JSON entry, a v1 lockfile with a different header, truncated/corrupted first line, or a file starting with an entry instead of a header.","commonSituations":"Hand-editing dagger.lock and deleting/altering the header; merge conflicts that mangled the first line; old lockfile formats from earlier Dagger versions; files truncated by failed writes.","solutions":["Restore the first content line to [[\"version\",\"2\"]] (run any dagger command to regenerate the lockfile)","Delete the corrupted lockfile and let Dagger regenerate it (then re-run dagger update to re-pin)","Check for git merge-conflict markers (<<<<<<<) near line 1 and resolve them"],"exampleFix":"// before (first content line)\n[\"mymod\",\"resolve\",{},\"sha256:...\"]\n// after\n[[\"version\",\"2\"]]\n[\"mymod\",\"resolve\",{},\"sha256:...\"]","handlingStrategy":"validation","validationCode":"lines := strings.Split(string(data), \"\\n\")\nfor _, l := range lines {\n    l = strings.TrimSpace(l)\n    if l == \"\" || strings.HasPrefix(l, \"#\") {\n        continue\n    }\n    if l != `[[\"version\",\"2\"]]` {\n        return fmt.Errorf(\"first content line is not a v2 version header\")\n    }\n    break\n}","typeGuard":null,"tryCatchPattern":"lock, err := lockfile.Parse(data)\nif err != nil && strings.HasPrefix(err.Error(), \"lockfile line \") {\n    // regenerate instead of failing the pipeline\n    lock = lockfile.New()\n}","preventionTips":["Never hand-edit the first content line of dagger.lock","Resolve merge conflicts by regenerating the lockfile rather than merging by hand","Commit lockfiles so corruption is visible in diffs and restorable from git"],"tags":["lockfile","parsing","versioning"],"backgroundTag":"invalid-lockfile-header","analyzedSha":"82ba2681dbe30d3547a1dc50ea495900ab5b6047","analyzedAt":"2026-09-05T07:21:37.930Z","contentChangedAt":"2026-09-05T07:21:37.930Z","schemaVersion":2},"datasetVersion":"2026-09-12T12:17:11.808Z"}