{"record":{"id":"442a615af2644d27","repo":"micro/go-micro","slug":"flow-duplicate-step-name-q","errorCode":null,"errorMessage":"flow: duplicate step name %q","messagePattern":"flow: duplicate step name %q","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"flow/steps.go","lineNumber":728,"sourceCode":"func (f *Flow) save(ctx context.Context, run Run) error {\n\tif f.checkpoint == nil {\n\t\treturn nil\n\t}\n\tif err := f.checkpoint.Save(ctx, run); err != nil {\n\t\tf.log.Logf(logger.ErrorLevel, \"Flow %s checkpoint save: %v\", f.name, err)\n\t\treturn fmt.Errorf(\"flow %s checkpoint save: %w\", f.name, err)\n\t}\n\treturn nil\n}\n\nfunc validateSteps(steps []Step) error {\n\tseen := make(map[string]struct{}, len(steps))\n\tfor i, step := range steps {\n\t\tif step.Name == \"\" {\n\t\t\treturn fmt.Errorf(\"flow: step %d has an empty name\", i)\n\t\t}\n\t\tif _, ok := seen[step.Name]; ok {\n\t\t\treturn fmt.Errorf(\"flow: duplicate step name %q\", step.Name)\n\t\t}\n\t\tseen[step.Name] = struct{}{}\n\t}\n\treturn nil\n}\n\nfunc stepIndex(steps []Step, name string) int {\n\tfor i, s := range steps {\n\t\tif s.Name == name {\n\t\t\treturn i\n\t\t}\n\t}\n\treturn -1\n}\n\nfunc resultFromRun(trigger string, run Run) Result {\n\tr := Result{\n\t\tFlowName:  run.Flow,","sourceCodeStart":710,"sourceCodeEnd":746,"githubUrl":"https://github.com/micro/go-micro/blob/24529f140421a11a33b6999ab7944f2021cfd69c/flow/steps.go#L710-L746","documentation":"flow.validateSteps maintains a 'seen' set and rejects a flow whose steps contain two steps with the same Name. Duplicate names make step references ambiguous, so the library refuses to build the flow. Raised at validation time, before execution.","triggerScenarios":"Passing a []Step to the flow builder where two entries have identical Name values; the error message includes the duplicated name in %q.","commonSituations":"Copy-pasting a step definition and forgetting to rename it; generating steps in a loop with a constant name; merging step lists from multiple sources where names collide.","solutions":["Rename one of the duplicate steps so all step names are unique.","Pre-check names client-side with a map before constructing the flow to get a clearer failure message.","If duplication is intentional (repeated logic), refactor into a named helper/loop instead of duplicating a step name."],"exampleFix":"// before\nsteps := []flow.Step{{Name: \"fetch\"}, {Name: \"fetch\"}}\n// after\nsteps := []flow.Step{{Name: \"fetch\"}, {Name: \"fetch-retry\"}}","handlingStrategy":"validation","validationCode":"seen := make(map[string]struct{}, len(steps))\nfor _, s := range steps {\n    if _, dup := seen[s.Name]; dup {\n        return fmt.Errorf(\"duplicate step name %q\", s.Name)\n    }\n    seen[s.Name] = struct{}{}\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Derive step names from an enum or constant list instead of free-form strings.","Run the same duplicate check in CI tests over all declared flows.","When copy-pasting a step, rename it immediately."],"tags":["go","flow","validation","duplicate"],"backgroundTag":"duplicate-identifier","analyzedSha":"24529f140421a11a33b6999ab7944f2021cfd69c","analyzedAt":"2026-09-01T02:52:24.923Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T05:18:18.240Z"}