{"record":{"id":"06ff6e57a6cd2de9","repo":"direnv/direnv","slug":"unclosed-quoted-value-in-env-file","errorCode":null,"errorMessage":"unclosed quoted value in .env file","messagePattern":"unclosed quoted value in \\.env file","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/dotenv/parse.go","lineNumber":116,"sourceCode":"\n\t\tmatch := lineRe.FindStringSubmatch(line)\n\t\t// commented or empty line\n\t\tif len(match) == 0 {\n\t\t\tcontinue\n\t\t}\n\t\tif len(match[1]) == 0 {\n\t\t\tcontinue\n\t\t}\n\n\t\tkey := match[1]\n\t\tvalue := match[2]\n\n\t\tparseValue(key, value, dotenv)\n\t}\n\n\t// If we end with an unclosed multi-line value, return an error\n\tif inMultiline {\n\t\treturn nil, fmt.Errorf(\"unclosed quoted value in .env file\")\n\t}\n\n\treturn dotenv, nil\n}\n\n// MustParse works the same as Parse but panics on error\nfunc MustParse(data string) map[string]string {\n\tenv, err := Parse(data)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\treturn env\n}\n\nfunc parseValue(key string, value string, dotenv map[string]string) {\n\tif len(value) <= 1 {\n\t\tdotenv[key] = value\n\t\treturn","sourceCodeStart":98,"sourceCodeEnd":134,"githubUrl":"https://github.com/direnv/direnv/blob/b00e451f547f39be7ab836d969054114a465a0f9/pkg/dotenv/parse.go#L98-L134","documentation":"The dotenv parser tracks multi-line quoted values; if input ends while a quoted value is still open (no closing quote on any subsequent line), Parse returns this error. It protects against silently truncating a value that was meant to span multiple lines.","triggerScenarios":"Parse() finishes reading the file while inMultiline is true — a value opened with `KEY=\"...` or `KEY='...` never received its closing quote before EOF.","commonSituations":"A quote deleted accidentally during editing; copying a multi-line secret (PEM key, JSON) into .env and missing the final quote; text editors truncating the last line; shell heredoc mistakes when generating .env.","solutions":["Add the missing closing quote to the value in the .env file","Check the last value in the file — the unclosed one starts there","For multi-line content prefer single-quoted multi-line values and ensure EOF terminates after the quote","Regenerate the .env from a template to restore lost characters"],"exampleFix":"// before\nPRIVATE_KEY=\"-----BEGIN RSA PRIVATE KEY-----\nMIIE...\n// after\nPRIVATE_KEY=\"-----BEGIN RSA PRIVATE KEY-----\nMIIE...\n-----END RSA PRIVATE KEY-----\"","handlingStrategy":"validation","validationCode":"awk \"'{n+=gsub(/\\\"/,\"\\\"\")} END{if (n%2) exit 1}' .env || echo 'unbalanced quotes'","typeGuard":null,"tryCatchPattern":"env, err := dotenv.Parse(data)\nif err != nil { return fmt.Errorf(\"dotenv parse: %w\", err) } // catches unclosed quote too","preventionTips":["Always close multi-line quoted values before EOF","Use single quotes for multi-line secrets like PEM keys","Avoid hand-editing large .env values; generate from templates","Count quotes when editing values with embedded quotes"],"tags":["dotenv","parse","quotes","multiline"],"backgroundTag":"unclosed-quoted-value","analyzedSha":"b00e451f547f39be7ab836d969054114a465a0f9","analyzedAt":"2026-09-05T21:39:49.983Z","contentChangedAt":"2026-09-05T21:39:49.983Z","schemaVersion":2},"datasetVersion":"2026-09-12T22:17:10.623Z"}