{"record":{"id":"55a0ece1d8cc9648","repo":"ory/kratos","slug":"invalid-uuid-in-start-after-q","errorCode":null,"errorMessage":"invalid UUID in --start-after %q","messagePattern":"invalid UUID in --start-after %q","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"cmd/migrate/normalize_phone_handler.go","lineNumber":134,"sourceCode":"\ntype tableConfig struct {\n\tkey         string\n\tname        string\n\tselectQuery string\n\tupdateQuery string\n}\n\n// parseStartAfter parses --start-after flags of the form \"key=uuid\".\nfunc parseStartAfter(args []string) (map[string]uuid.UUID, error) {\n\tresult := make(map[string]uuid.UUID)\n\tfor _, arg := range args {\n\t\tkey, val, ok := strings.Cut(arg, \"=\")\n\t\tif !ok {\n\t\t\treturn nil, errors.Errorf(\"invalid --start-after format %q: expected key=uuid (e.g. credentials=<id>)\", arg)\n\t\t}\n\t\tid, err := uuid.FromString(val)\n\t\tif err != nil {\n\t\t\treturn nil, errors.Wrapf(err, \"invalid UUID in --start-after %q\", arg)\n\t\t}\n\t\tresult[key] = id\n\t}\n\treturn result, nil\n}\n\nfunc printSummary(cmd *cobra.Command, tables []tableConfig, allStats []normalizeStats) {\n\tout := cmd.OutOrStdout()\n\n\t_, _ = fmt.Fprintln(out)\n\n\ttw := tabwriter.NewWriter(out, 0, 0, 2, ' ', 0)\n\t_, _ = fmt.Fprintln(tw, \"\\tSCANNED\\tUPDATED\\tSKIPPED\\tERRORS\")\n\n\tvar total normalizeStats\n\tfor i, table := range tables {\n\t\ts := allStats[i]\n\t\t_, _ = fmt.Fprintf(tw, \"%s\\t%d\\t%d\\t%d\\t%d\\n\", table.name, s.scanned, s.updated, s.skipped, s.errors)","sourceCodeStart":116,"sourceCodeEnd":152,"githubUrl":"https://github.com/ory/kratos/blob/b86338da04a040247a07f46100a86dcfb3875909/cmd/migrate/normalize_phone_handler.go#L116-L152","documentation":"parseStartAfter validates that the value part of a \"key=uuid\" --start-after argument is a valid UUID via uuid.FromString. If parsing fails, the underlying UUID parse error is wrapped with \"invalid UUID in --start-after <arg>\". Raised before any database work, purely from CLI input validation.","triggerScenarios":"Passing --start-after credentials=not-a-uuid, a truncated UUID, a different ID format (e.g. numeric ID), or an empty value after '='.","commonSituations":"Hand-copying an ID from logs with typos or truncation, using a non-UUID primary key from a different table, or forgetting the ID entirely after the '=' sign.","solutions":["Copy the exact UUID from the previous run's resume output or the database id column.","Verify the value is a 36-character hyphenated UUID (8-4-4-4-12).","Quote the argument to prevent shell mangling."],"exampleFix":"// before\nkratos migrate normalize-phone --start-after credentials=abc123\n// after\nkratos migrate normalize-phone --start-after credentials=018f3c2e-3f4a-7b8c-9d0e-1f2a3b4c5d6e","handlingStrategy":"validation","validationCode":"re := 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}$`)\nif !re.MatchString(val) {\n    return fmt.Errorf(\"not a UUID: %q\", val)\n}","typeGuard":"func isUUID(s string) bool {\n    _, err := uuid.Parse(s)\n    return err == nil\n}","tryCatchPattern":"null","preventionTips":["Copy IDs directly from the resume output or database, never retype them","Validate UUID shape in wrapper scripts before invoking the CLI","Confirm the ID source table uses UUID primary keys"],"tags":["cli","uuid","argument-parsing"],"backgroundTag":"invalid-identifier-format","analyzedSha":"b86338da04a040247a07f46100a86dcfb3875909","analyzedAt":"2026-09-07T15:58:15.934Z","contentChangedAt":"2026-09-07T15:58:15.934Z","schemaVersion":2},"datasetVersion":"2026-09-16T09:17:16.951Z"}