{"record":{"id":"f681e9032b3ed3c6","repo":"Billionmail/BillionMail","slug":"add-up-to-3-urls","errorCode":null,"errorMessage":"Add up to 3 URLs","messagePattern":"Add up to 3 URLs","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"core/internal/service/askai/project.go","lineNumber":152,"sourceCode":"\t\treturn fmt.Errorf(\"error marshalling project configuration: %v\", err)\n\t}\n\tconfig.UpdateTime = public.GetNowTime() // Update the time before saving\n\terr = os.WriteFile(filename, configStr, os.ModePerm)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error writing project configuration file: %v\", err)\n\t}\n\treturn nil\n}\n\n// Create initializes a new project configuration with the provided domain and URLs.\n// It sets default values for other fields and saves the configuration to a file.\nfunc Create(Domain string, urls []string) error {\n\turlsCount := len(urls)\n\tif urls == nil || urlsCount == 0 {\n\t\turls = append(urls, \"http://\"+Domain) // Default URL if none provided\n\t}\n\tif urlsCount > 3 {\n\t\treturn fmt.Errorf(\"Add up to 3 URLs\")\n\t}\n\t// Ensure all URLs start with \"http://\"\n\tfor i, urlStr := range urls {\n\t\tif !strings.HasPrefix(urlStr, \"http\") {\n\t\t\turls[i] = \"http://\" + urlStr\n\t\t}\n\t}\n\n\tvar config ProjectConfig = ProjectConfig{\n\t\tDomain:        Domain,\n\t\tUrls:          urls,\n\t\tProjectName:   \"\",\n\t\tDescription:   \"\",\n\t\tIndustry:      \"\",\n\t\tPrimaryLogo:   \"\",\n\t\tSecondaryLogo: \"\",\n\t\tFavicon:       \"\",\n\t\tStatus:        true, // Default status is active","sourceCodeStart":134,"sourceCodeEnd":170,"githubUrl":"https://github.com/Billionmail/BillionMail/blob/fc36c76c050c3775c5e899faf7403cf0262d2744/core/internal/service/askai/project.go#L134-L170","documentation":"Guard in askai project Create: the caller passed a nil or empty urls slice when creating a project. The code substitutes a default URL list and caps it, so this message reflects the 'Add up to 3 URLs' constraint applied to project initialization.","triggerScenarios":"Calling askai.Create(Domain, urls) where len(urls) > 3 — e.g. a frontend submitting a multi-URL form without a client-side limit or a bulk import passing many seed URLs.","commonSituations":"A form allowing unlimited URL inputs; an API consumer batching all site variants (www, m., blog) into one Create call; migrating data from another tool with more seed URLs per project.","solutions":["Limit the urls slice to 3 entries before calling Create (truncate or reject in the UI/API layer)","Split into multiple projects if more than 3 seed URLs are genuinely needed","Note the quirk: the count check uses the original urlsCount even if urls was nil; always pass a non-nil slice of at most 3 URLs"],"exampleFix":"// before\nurls := []string{\"a.com\", \"b.com\", \"c.com\", \"d.com\"}\naskai.Create(domain, urls) // error\n// after\nif len(urls) > 3 { urls = urls[:3] }\naskai.Create(domain, urls)","handlingStrategy":"validation","validationCode":"if len(urls) > 3 {\n    return errors.New(\"askai.Create accepts at most 3 URLs\")\n}\nif len(urls) == 0 {\n    urls = []string{\"http://\" + domain}\n}","typeGuard":null,"tryCatchPattern":"if err := askai.Create(domain, urls); err != nil {\n    if strings.Contains(err.Error(), \"Add up to 3 URLs\") {\n        return fmt.Errorf(\"please select at most 3 seed URLs (got %d)\", len(urls))\n    }\n    return err\n}","preventionTips":["Enforce a 3-URL limit in the frontend form (max items) before submit","Truncate or reject URL lists at the API boundary before calling Create","Document the 3-URL cap in API docs for consumers","Split large sites into multiple projects if more seed URLs are needed"],"tags":["go","validation","input-limits","project"],"backgroundTag":"input-validation-failed","analyzedSha":"fc36c76c050c3775c5e899faf7403cf0262d2744","analyzedAt":"2026-09-05T21:28:54.019Z","contentChangedAt":"2026-09-05T21:28:54.019Z","schemaVersion":2},"datasetVersion":"2026-09-12T22:17:10.623Z"}