{"record":{"id":"173ee51c5d7a9aac","repo":"v2rayA/v2rayA","slug":"tag-s-already-exists","errorCode":null,"errorMessage":"tag '%s' already exists","messagePattern":"tag '(.+?)' already exists","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"service/server/controller/customInbound.go","lineNumber":92,"sourceCode":"\t\thardcodeReplacement := regexp.MustCompile(`\\$\\$.+?\\$\\$`)\n\t\tfor i := range lines {\n\t\t\thardcodes := hardcodeReplacement.FindAllString(lines[i], -1)\n\t\t\tfor _, hardcode := range hardcodes {\n\t\t\t\tlines[i] = strings.Replace(lines[i], hardcode, \"\", 1)\n\t\t\t}\n\t\t}\n\t\t_, err := RoutingA.Parse(strings.Join(lines, \"\\n\"))\n\t\tif err != nil {\n\t\t\tcommon.ResponseError(ctx, logError(fmt.Errorf(\"invalid RoutingA rules: %w\", err)))\n\t\t\treturn\n\t\t}\n\t}\n\n\tinbounds := configure.GetCustomInbounds()\n\t// check duplicate tag and port\n\tfor _, existing := range inbounds {\n\t\tif existing.Tag == ci.Tag {\n\t\t\tcommon.ResponseError(ctx, logError(fmt.Errorf(\"tag '%s' already exists\", ci.Tag)))\n\t\t\treturn\n\t\t}\n\t\tif existing.Port == ci.Port {\n\t\t\tcommon.ResponseError(ctx, logError(fmt.Errorf(\"port %d is already in use by '%s'\", ci.Port, existing.Tag)))\n\t\t\treturn\n\t\t}\n\t}\n\tinbounds = append(inbounds, ci)\n\tif err := configure.SetCustomInbounds(inbounds); err != nil {\n\t\tcommon.ResponseError(ctx, logError(err))\n\t\treturn\n\t}\n\tcommon.ResponseSuccess(ctx, gin.H{\"inbounds\": inbounds})\n}\n\nfunc DeleteCustomInbound(ctx *gin.Context) {\n\tvar req struct {\n\t\tTag string `json:\"tag\"`","sourceCodeStart":74,"sourceCodeEnd":110,"githubUrl":"https://github.com/v2rayA/v2rayA/blob/71e5442fc548c05680ee55eae943e6c0afe9ac51/service/server/controller/customInbound.go#L74-L110","documentation":"PostCustomInbound rejects creation of a custom inbound whose Tag matches an existing inbound's tag. Tags are unique identifiers used by the core to reference inbounds, so duplicates would create ambiguous references. The check iterates all configured custom inbounds before saving.","triggerScenarios":"POST to the custom inbound API with a 'tag' field identical to any existing custom inbound's tag.","commonSituations":"Re-submitting a form after a partial failure; client retry duplicating a successfully created inbound; copying an inbound definition and forgetting to change the tag.","solutions":["Choose a different, unique tag for the new inbound","List existing inbounds first and pick an unused tag","Delete the old inbound with the same tag if it is no longer needed","Make the client idempotent: check for existence before POSTing"],"exampleFix":"// before\n{ \"tag\": \"inbound-1\", \"port\": 1080, ... }\n// after\n{ \"tag\": \"inbound-2\", \"port\": 1080, ... }","handlingStrategy":"validation","validationCode":"inbounds := configure.GetCustomInbounds()\nif inbounds.Any(func(i configure.CustomInbound) bool { return i.Tag == newTag }) {\n\treturn fmt.Errorf(\"tag %q already exists\", newTag)\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Generate unique tags programmatically (prefix + counter/uuid)","List existing inbounds before creating","Make client retries idempotent by checking existence first"],"tags":["duplicate-tag","api","config-validation"],"backgroundTag":"duplicate-resource-tag","analyzedSha":"71e5442fc548c05680ee55eae943e6c0afe9ac51","analyzedAt":"2026-09-05T20:04:37.459Z","contentChangedAt":"2026-09-05T20:04:37.459Z","schemaVersion":2},"datasetVersion":"2026-09-12T22:17:10.623Z"}