{"record":{"id":"4e33e67b53c6c45b","repo":"hashicorp/consul","slug":"failed-to-convert","errorCode":null,"errorMessage":"Failed to convert ","messagePattern":"Failed to convert ","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"api/event.go","lineNumber":111,"sourceCode":"\tvar entries []*UserEvent\n\tif err := decodeBody(resp, &entries); err != nil {\n\t\treturn nil, nil, err\n\t}\n\treturn entries, qm, nil\n}\n\n// IDToIndex is a bit of a hack. This simulates the index generation to\n// convert an event ID into a WaitIndex.\nfunc (e *Event) IDToIndex(uuid string) uint64 {\n\tlower := uuid[0:8] + uuid[9:13] + uuid[14:18]\n\tupper := uuid[19:23] + uuid[24:36]\n\tlowVal, err := strconv.ParseUint(lower, 16, 64)\n\tif err != nil {\n\t\tpanic(\"Failed to convert \" + lower)\n\t}\n\thighVal, err := strconv.ParseUint(upper, 16, 64)\n\tif err != nil {\n\t\tpanic(\"Failed to convert \" + upper)\n\t}\n\treturn lowVal ^ highVal\n}\n","sourceCodeStart":93,"sourceCodeEnd":115,"githubUrl":"https://github.com/hashicorp/consul/blob/2397ff0d763d34f2fe37fe59fde6a7f7fc430a3e/api/event.go#L93-L115","documentation":"Event.IDToIndex converts a Consul event ID (a UUID) into a synthetic index so clients can blocking-query over the event list (api/watch uses it at funcs.go:259). It slices the canonical 36-character dashed UUID into two 16-hex-digit halves and XORs the parsed values. If any segment is not valid hexadecimal the ParseUint fails and the function panics; strings shorter than 36 chars panic even earlier with a slice-bounds error.","triggerScenarios":"Calling IDToIndex with a non-canonical ID: empty string, non-hex characters, a truncated ID, or an ID produced by a non-Consul producer. The events API returns canonical UUIDs, so this fires on malformed or hand-constructed input passed by caller code.","commonSituations":"Passing user-supplied or config-file event IDs straight into IDToIndex; blocking-query watch code receiving unexpected event payloads; test fixtures using fake IDs like 'test-event'.","solutions":["Validate the ID is a canonical 36-char dashed UUID before calling IDToIndex","Use the ID exactly as returned by the API (Event.ID from Event.List) rather than reconstructing it","If IDs may be non-standard, wrap the call in a recovering helper that returns an error instead of crashing","Fix the upstream producer generating malformed IDs"],"exampleFix":"// before\nidx := events.IDToIndex(rawID) // panics on malformed ID\n\n// after\nif !isValidUUID(rawID) {\n    return fmt.Errorf(\"event id %q is not a canonical UUID\", rawID)\n}\nidx := events.IDToIndex(rawID)","handlingStrategy":"validation","validationCode":"// guard before calling IDToIndex\nvar canonicalUUID = regexp.MustCompile(`^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$`)\n\nfunc safeIDToIndex(e *api.Event, id string) (uint64, error) {\n    if !canonicalUUID.MatchString(id) {\n        return 0, fmt.Errorf(\"event id %q is not a canonical UUID\", id)\n    }\n    return e.IDToIndex(id), nil\n}","typeGuard":"func isCanonicalUUID(s string) bool {\n    if len(s) != 36 || s[8] != '-' || s[13] != '-' || s[18] != '-' || s[23] != '-' {\n        return false\n    }\n    for _, r := range s {\n        if r == '-' {\n            continue\n        }\n        if !strings.ContainsRune(\"0123456789abcdefABCDEF\", r) {\n            return false\n        }\n    }\n    return true\n}","tryCatchPattern":"// Go has no try/catch; wrap the call with a recovering helper in\ncode that ingests external IDs\nfunc recoveringIDToIndex(e *api.Event, id string) (idx uint64, err error) {\n    defer func() {\n        if r := recover(); r != nil {\n            err = fmt.Errorf(\"IDToIndex panicked for id %q: %v\", id, r)\n        }\n    }()\n    return e.IDToIndex(id), nil\n}","preventionTips":["Only feed IDs obtained from Event.List/Event.Fire output into IDToIndex","Validate external/config-supplied event IDs against a UUID pattern before use","In watch code (api/watch), keep goroutines resilient: a malformed ID crashes the watch handler otherwise"],"tags":["go","consul-api","uuid","panic","blocking-query"],"backgroundTag":null,"analyzedSha":"2397ff0d763d34f2fe37fe59fde6a7f7fc430a3e","analyzedAt":"2026-08-15T19:19:47.700Z","schemaVersion":2},"datasetVersion":"2026-08-16T03:17:38.424Z"}