{"record":{"id":"a2c3602a02df7125","repo":"pulumi/pulumi","slug":"first-path-segement-of-config-key-must-be-a-string","errorCode":null,"errorMessage":"first path segement of config key must be a string","messagePattern":"first path segement of config key must be a string","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"sdk/go/common/resource/config/map.go","lineNumber":345,"sourceCode":"\treturn nil\n}\n\n// parseKeyPath returns the property paths in the key and a new config key with the first\n// path segment as the name.\nfunc parseKeyPath(k Key) (resource.PropertyPath, Key, error) {\n\t// Parse the path, which will be in the name portion of the key.\n\tp, err := resource.ParsePropertyPathStrict(k.Name())\n\tif err != nil {\n\t\treturn nil, Key{}, fmt.Errorf(\"invalid config key path: %w\", err)\n\t}\n\tif len(p) == 0 {\n\t\treturn nil, Key{}, errors.New(\"empty config key path\")\n\t}\n\n\t// Create a new key that has the first path segment as the name.\n\tfirstKey, ok := p[0].(string)\n\tif !ok {\n\t\treturn nil, Key{}, errors.New(\"first path segement of config key must be a string\")\n\t}\n\tif firstKey == \"\" {\n\t\treturn nil, Key{}, errors.New(\"config key is empty\")\n\t}\n\n\tconfigKey := MustMakeKey(k.Namespace(), firstKey)\n\n\treturn p, configKey, nil\n}\n","sourceCodeStart":327,"sourceCodeEnd":355,"githubUrl":"https://github.com/pulumi/pulumi/blob/793f7b2e160db4321fb7fb6b0607461e01cb251e/sdk/go/common/resource/config/map.go#L327-L355","documentation":"parseKeyPath takes the first parsed path segment and uses it as the new config key's name. Since config keys are named by strings, the first segment must be a string; if the strict parser produced a non-string first accessor (e.g. an integer), this error is returned. (Note: the message contains the known typo \"segement\".)","triggerScenarios":"Using a key name whose first path accessor is an index rather than a property name, e.g. a key named `[0].sub` or `[42]` — ParsePropertyPathStrict succeeds (it is a valid path) but p[0] is an int.","commonSituations":"Mistakenly putting an array index at the root of a config key path; generating keys programmatically where a numeric segment lands first; misunderstanding that the root must always be a named property.","solutions":["Make the first path segment a property name, e.g. use `list[0]` instead of `[0]`","If you need array roots, nest them under a named key so the first accessor is a string","Validate with resource.ParsePropertyPathStrict and assert the first element is a string before calling the Map API"],"exampleFix":"// before\nk := config.MustMakeKey(\"app\", \"[0].port\") // first accessor is an int\n// after\nk := config.MustMakeKey(\"app\", \"ports[0]\") // first accessor is a string","handlingStrategy":"validation","validationCode":"p, err := resource.ParsePropertyPathStrict(keyName)\nif err != nil { return err }\nif _, ok := p[0].(string); !ok {\n    return fmt.Errorf(\"config key %q must start with a property name, not an index\", keyName)\n}","typeGuard":"func startsWithStringSeg(p resource.PropertyPath) bool {\n    _, ok := p[0].(string)\n    return len(p) > 0 && ok\n}","tryCatchPattern":"if err != nil && strings.Contains(err.Error(), \"must be a string\") { /* rewrite path so first segment is a name */ }","preventionTips":["Always put a property name before any [index] accessors","Remember config keys are name-rooted; arrays must hang off a named key","Validate paths programmatically before use"],"tags":["go","config","property-path","validation"],"backgroundTag":"invalid-config-key-path","analyzedSha":"793f7b2e160db4321fb7fb6b0607461e01cb251e","analyzedAt":"2026-08-31T09:36:43.099Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}