{"record":{"id":"37be353f47d4be16","repo":"pulumi/pulumi","slug":"unclosed-string-s","errorCode":null,"errorMessage":"unclosed string [%s","messagePattern":"unclosed string \\[(.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"sdk/go/property/glob.go","lineNumber":189,"sourceCode":"\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tif len(runes) < i || runes[i] != ']' {\n\t\t\treturn nil, nil, fmt.Errorf(\"unclosed index [%s\", string(runes[:i]))\n\t\t}\n\t\tn, err := strconv.ParseUint(string(runes[0:i]), 10, 64)\n\t\tif err != nil {\n\t\t\treturn nil, nil, err\n\t\t}\n\t\tif n > math.MaxInt64 {\n\t\t\treturn nil, nil, fmt.Errorf(\"indexes cannot exceed %d\", int64(math.MaxInt64))\n\t\t}\n\t\treturn IndexSegment{n}, runes[i+1:], nil\n\tcase runes[0] == '\"':\n\t\ti := 1\n\t\tfor ; ; i++ {\n\t\t\tif len(runes) <= i {\n\t\t\t\treturn nil, nil, fmt.Errorf(`unclosed string [%s`, string(runes))\n\t\t\t}\n\t\t\tif runes[i] == '\"' {\n\t\t\t\tif len(runes) <= i+1 || runes[i+1] != ']' {\n\t\t\t\t\treturn nil, nil, fmt.Errorf(`unclosed index [%s`, string(runes[:i+1]))\n\t\t\t\t}\n\t\t\t\tkey, err := strconv.Unquote(string(runes[:i+1]))\n\t\t\t\treturn KeySegment{key}, runes[i+2:], err\n\t\t\t}\n\t\t\tif runes[i] == '\\\\' {\n\t\t\t\ti++\n\t\t\t}\n\t\t}\n\tcase runes[0] == '*':\n\t\tif len(runes) == 1 || runes[1] != ']' {\n\t\t\treturn nil, nil, errors.New(`expected ']' after \"[*\"`)\n\t\t}\n\t\treturn Splat, runes[2:], nil\n\tdefault:","sourceCodeStart":171,"sourceCodeEnd":207,"githubUrl":"https://github.com/pulumi/pulumi/blob/793f7b2e160db4321fb7fb6b0607461e01cb251e/sdk/go/property/glob.go#L171-L207","documentation":"For quoted string keys ('[\"key\"]'), parseIndex scans for the closing double quote. If the input ends before a '\"' is found, the string (and the bracket) was never terminated; the error echoes the entire remaining input, e.g. 'unclosed string [\"abc'.","triggerScenarios":"UnmarshalText with input like `arr[\"key` or `arr[\"key\\\\` (trailing backslash escapes the end as the loop skips one char) — the closing quote never appears before end of input.","commonSituations":"Manually building quoted keys without strconv.Quote, truncation during serialization, or escaping mistakes where a stray backslash swallows the closing quote.","solutions":["Close the quoted key with '\"' and the bracket with ']': `arr[\"key\"]`.","Build the quoted segment with %q or strconv.Quote rather than hand-concatenating quotes.","Check for a trailing backslash that escapes the closing quote and double it if a literal backslash is intended."],"exampleFix":"// before\nerr := g.UnmarshalText([]byte(`arr[\"key`)) // unclosed string [\"key\n// after\nerr := g.UnmarshalText([]byte(`arr[\"key\"]`))\n// or build safely\nquoted := fmt.Sprintf(\"arr[%s]\", strconv.Quote(\"key\"))\nerr := g.UnmarshalText([]byte(quoted))","handlingStrategy":"validation","validationCode":"re := regexp.MustCompile(`^\\[\"(?:[^\"\\\\]|\\\\.)*\"\\]$`)\nfor _, m := range bracketRe.FindAllString(globStr, -1) {\n\tif strings.HasPrefix(m, `[\"`) && !re.MatchString(m) {\n\t\treturn fmt.Errorf(\"malformed quoted key segment %q\", m)\n\t}\n}","typeGuard":null,"tryCatchPattern":"var g property.Glob\nif err := g.UnmarshalText([]byte(globStr)); err != nil {\n\treturn fmt.Errorf(\"cannot parse glob %q: %w\", globStr, err)\n}","preventionTips":["Build quoted segments with strconv.Quote / %q, never by hand","Ensure quoted keys are closed with \"] — check for trailing backslash that escapes the closing quote","Round-trip globs through MarshalText before use"],"tags":["go","parsing","glob","property-path"],"backgroundTag":"unclosed-bracket","analyzedSha":"793f7b2e160db4321fb7fb6b0607461e01cb251e","analyzedAt":"2026-08-31T09:36:43.099Z","schemaVersion":2},"datasetVersion":"2026-09-01T08:17:40.651Z"}