{"record":{"id":"b385b7b9f84fcf2e","repo":"Billionmail/BillionMail","slug":"failed-to-update-alias-v","errorCode":null,"errorMessage":"failed to update alias: %v","messagePattern":"failed to update alias: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"core/internal/service/domains/domains.go","lineNumber":63,"sourceCode":"func setCatchall(ctx context.Context, domainName, catchall string) error {\n\taddress := fmt.Sprintf(\"@%s\", domainName)\n\tif catchall != \"\" {\n\t\tvar count int\n\t\tcount, err := g.DB().Model(\"alias\").\n\t\t\tWhere(\"address\", address).\n\t\t\tWhere(\"domain\", domainName).\n\t\t\tCount()\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"failed to check alias existence: %v\", err)\n\t\t}\n\t\tif count > 0 {\n\t\t\t_, err = g.DB().Model(\"alias\").\n\t\t\t\tWhere(\"address\", address).\n\t\t\t\tWhere(\"domain\", domainName).\n\t\t\t\tData(g.Map{\"goto\": catchall, \"active\": 1, \"update_time\": time.Now().Unix()}).\n\t\t\t\tUpdate()\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"failed to update alias: %v\", err)\n\t\t\t}\n\t\t} else {\n\t\t\t_, err = g.DB().Model(\"alias\").Data(g.Map{\n\t\t\t\t\"address\":     address,\n\t\t\t\t\"goto\":        catchall,\n\t\t\t\t\"domain\":      domainName,\n\t\t\t\t\"active\":      1,\n\t\t\t\t\"create_time\": time.Now().Unix(),\n\t\t\t\t\"update_time\": time.Now().Unix(),\n\t\t\t}).Insert()\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"failed to insert alias: %v\", err)\n\t\t\t}\n\t\t}\n\t} else {\n\t\t// catchall is empty, disabled\n\t\t_, _ = g.DB().Model(\"alias\").\n\t\t\tWhere(\"address\", address).","sourceCodeStart":45,"sourceCodeEnd":81,"githubUrl":"https://github.com/Billionmail/BillionMail/blob/fc36c76c050c3775c5e899faf7403cf0262d2744/core/internal/service/domains/domains.go#L45-L81","documentation":"setCatchall wraps a DB UPDATE on the `alias` table (setting the catchall `goto` target for the catchall address of a domain) when the row fails to update. GoFrame's Model.Update() returns the underlying PostgreSQL driver error, and this wrapper adds context that the alias update step of domain Add/Update failed. It means the catchall forwarding record could not be persisted.","triggerScenarios":"Calling domains.Add or domains.Update with a non-empty Catchall when the UPDATE ... WHERE address=<catchall address> AND domain=<domain> fails — e.g. DB connection down, alias table missing/locked, constraint violation, or the row was concurrently deleted between the earlier count query and the update.","commonSituations":"Postgres container stopped or unreachable; `alias` table dropped by a failed migration; database user lacking UPDATE privilege on alias; deadlocks from concurrent domain edits; duplicate catchall rows causing unexpected affected-row behavior.","solutions":["Verify PostgreSQL is reachable and the `alias` table exists (check the wrapped %v detail for connection vs SQL errors)","Check the DB user has UPDATE privilege on the alias table","Inspect for concurrent deletes/unique constraints on (address, domain) and re-run the domain update","Recreate the catchall alias row manually if it was deleted mid-operation, then retry"],"exampleFix":"// before\n_, err = g.DB().Model(\"alias\").Where(\"address\", address).Where(\"domain\", domainName).Data(...).Update()\n// after\nresult, err := g.DB().Model(\"alias\").Where(\"address\", address).Where(\"domain\", domainName).Data(g.Map{\"goto\": catchall, \"active\": 1}).Update()\nif err != nil { return fmt.Errorf(\"failed to update alias: %v\", err) }\nif n, _ := result.RowsAffected(); n == 0 { return fmt.Errorf(\"catchall alias %s not found for domain %s\", address, domainName) }","handlingStrategy":"try-catch","validationCode":"var n int\ncountErr := g.DB().Model(\"alias\").Where(\"address\", address).Where(\"domain\", domainName).Count(&n)\nif countErr != nil { return fmt.Errorf(\"alias table unavailable: %v\", countErr) }","typeGuard":null,"tryCatchPattern":"result, err := g.DB().Model(\"alias\").Where(...).Data(...).Update()\nif err != nil {\n    if strings.Contains(err.Error(), \"connection refused\") { /* surface DB-down to admin UI */ }\n    return fmt.Errorf(\"failed to update alias: %v\", err)\n}","preventionTips":["Health-check PostgreSQL before domain mutations","Keep migrations ensuring the alias table run at startup","Avoid concurrent edits to the same domain (lock or optimistic versioning)","Log the wrapped driver error verbatim for diagnosis"],"tags":["database","postgresql","goframe","alias"],"backgroundTag":"database-update-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"}