{"record":{"id":"d282dd2900e0ed7f","repo":"Tencent/WeKnora","slug":"create-default-s-page-w","errorCode":null,"errorMessage":"create default %s page: %w","messagePattern":"create default (.+?) page: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/application/service/wiki_page.go","lineNumber":1273,"sourceCode":"\t\treturn nil, fmt.Errorf(\"get knowledge base: %w\", err)\n\t}\n\n\tpage := &types.WikiPage{\n\t\tID:              uuid.New().String(),\n\t\tTenantID:        kb.TenantID,\n\t\tKnowledgeBaseID: kbID,\n\t\tSlug:            slug,\n\t\tTitle:           title,\n\t\tPageType:        pageType,\n\t\tStatus:          types.WikiPageStatusPublished,\n\t\tContent:         content,\n\t\tSummary:         title,\n\t\tVersion:         1,\n\t}\n\tnormalizeWikiHierarchy(page)\n\n\tif err := s.repo.Create(ctx, page); err != nil {\n\t\treturn nil, fmt.Errorf(\"create default %s page: %w\", slug, err)\n\t}\n\treturn page, nil\n}\n\nfunc normalizeWikiHierarchy(page *types.WikiPage) {\n\tif page == nil {\n\t\treturn\n\t}\n\tpage.ParentSlug = strings.TrimSpace(page.ParentSlug)\n\n\tcleanPath := types.StringArray(types.CleanWikiCategoryPath(page.CategoryPath))\n\tpage.CategoryPath = cleanPath\n\tpage.Depth = len(cleanPath)\n\n\tdisplay := strings.TrimSpace(page.Title)\n\tif display == \"\" {\n\t\tdisplay = strings.TrimSpace(page.Slug)\n\t}","sourceCodeStart":1255,"sourceCodeEnd":1291,"githubUrl":"https://github.com/Tencent/WeKnora/blob/988cbb03305e055d8ebb7d46d9ac6cc0803cd074/internal/application/service/wiki_page.go#L1255-L1291","documentation":"After constructing the default page, createDefaultPage persists it via s.repo.Create. Failure is wrapped as 'create default <slug> page: %w'. This means seeding the default index page failed at the storage layer.","triggerScenarios":"GetIndex triggering default-page creation when repo.Create fails — unique constraint on slug/ID, DB connection failure, read-only replica, or context cancellation.","commonSituations":"Two concurrent first requests racing to create the same default page (duplicate key); database out of disk or locked; schema mismatch after migration; wrong tenant configuration.","solutions":["Check the wrapped cause: for duplicate-key errors, treat the page as already created and retry the read (or add an upsert/OnConflict path).","Retry the GetIndex call after transient DB failures.","Verify migrations and constraints on the pages table.","Serialize or idempotently guard default-page seeding to avoid concurrent-create races."],"exampleFix":"// before\nif err := s.repo.Create(ctx, page); err != nil {\n    return nil, fmt.Errorf(\"create default %s page: %w\", slug, err)\n}\n// after\nif err := s.repo.Create(ctx, page); err != nil {\n    if existing, getErr := s.repo.GetBySlug(ctx, page.KnowledgeBaseID, slug); getErr == nil {\n        return existing, nil // lost race; page already exists\n    }\n    return nil, fmt.Errorf(\"create default %s page: %w\", slug, err)\n}","handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"page, err := svc.GetIndex(ctx, kbID)\nif err != nil && strings.Contains(err.Error(), \"create default\") {\n    if isDuplicateKey(err) {\n        page, err = svc.GetIndex(ctx, kbID) // lost race; re-read\n    } else if isTransient(err) {\n        time.Sleep(backoff)\n        page, err = svc.GetIndex(ctx, kbID)\n    }\n}","preventionTips":["Make default-page seeding idempotent (upsert or get-or-create)","Avoid concurrent first-access storms by warming default pages after KB creation","Keep pages-table constraints and migrations current","Retry with backoff on transient storage errors"],"tags":["database","persistence","race-condition"],"backgroundTag":"database-insert-failed","analyzedSha":"988cbb03305e055d8ebb7d46d9ac6cc0803cd074","analyzedAt":"2026-09-02T14:41:08.344Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}