diff --git a/services/search/pkg/bleve/index.go b/services/search/pkg/bleve/index.go index f541b1941a..50726b97be 100644 --- a/services/search/pkg/bleve/index.go +++ b/services/search/pkg/bleve/index.go @@ -62,7 +62,7 @@ func NewIndex(root string) (bleve.Index, searchmapping.Classification, error) { switch classification.Verdict { case searchmapping.VerdictBreaking: _ = index.Close() - return nil, classification, searchmapping.ManualActionRequiredError(destination, "delete the index directory "+destination, classification.Reasons) + return nil, classification, searchmapping.ManualActionRequiredError(destination, classification.Reasons) case searchmapping.VerdictAdditive: // Safe: everything else is identical and the new fields hold no data. // Reopen so the live mapping picks the change up; otherwise the fields diff --git a/services/search/pkg/mapping/classify.go b/services/search/pkg/mapping/classify.go index 696980e0fc..2e0e7e100a 100644 --- a/services/search/pkg/mapping/classify.go +++ b/services/search/pkg/mapping/classify.go @@ -13,20 +13,16 @@ import ( // ErrManualActionRequired marks schema changes that cannot be applied in place. var ErrManualActionRequired = errors.New("manual action required") -// ManualActionRequiredError builds the operator-facing error for a breaking -// schema change. index names the index, deleteStep is the engine-specific -// instruction to remove it. -func ManualActionRequiredError(index, deleteStep string, reasons []string) error { +// ManualActionRequiredError reports a breaking schema change. Because the index +// is versioned by search.SchemaVersion, a released instance never hits this: a +// version bump builds a fresh index. It fires in development when the mapping is +// changed in a breaking way without bumping search.SchemaVersion, so the fix is +// to bump it (or revert the change). +func ManualActionRequiredError(index string, reasons []string) error { return fmt.Errorf( - "%w: search index %s was built with a different schema:\n - %s\n"+ - "There is no in-place migration: with the OpenCloud search service stopped, %s, "+ - "then start it again (an empty index with the new schema is created), "+ - "then rebuild the content by running: opencloud search index --all-spaces. "+ - "To bring the instance up without search until a maintenance window, "+ - "set OC_EXCLUDE_RUN_SERVICES=search; until the service is back, search "+ - "and features built on it (e.g. the search bar and the tag list) are "+ - "unavailable", - ErrManualActionRequired, index, strings.Join(reasons, "\n - "), deleteStep, + "%w: the search mapping in code differs from index %s in a breaking way:\n - %s\n"+ + "bump search.SchemaVersion to build a fresh index, or revert the mapping change", + ErrManualActionRequired, index, strings.Join(reasons, "\n - "), ) } diff --git a/services/search/pkg/opensearch/index.go b/services/search/pkg/opensearch/index.go index a457bc446a..3ead1bed48 100644 --- a/services/search/pkg/opensearch/index.go +++ b/services/search/pkg/opensearch/index.go @@ -179,7 +179,7 @@ func (m IndexManager) Apply(ctx context.Context, name string, client *opensearch ) reasons = append(reasons, classification.Reasons...) if len(reasons) > 0 { - return searchmapping.ManualActionRequiredError(name, fmt.Sprintf("delete the index (DELETE /%s)", name), reasons) + return searchmapping.ManualActionRequiredError(name, reasons) } if len(classification.NewFields) == 0 { return nil // schema is up to date @@ -196,7 +196,7 @@ func (m IndexManager) Apply(ctx context.Context, name string, client *opensearch case err != nil && errors.As(err, &putErr) && putErr.Err.Type == "illegal_argument_exception" && (strings.Contains(putErr.Err.Reason, "cannot be changed") || strings.Contains(putErr.Err.Reason, "Cannot update parameter")): // backstop, should be unreachable after the classification above - return searchmapping.ManualActionRequiredError(name, fmt.Sprintf("delete the index (DELETE /%s)", name), []string{putErr.Err.Reason}) + return searchmapping.ManualActionRequiredError(name, []string{putErr.Err.Reason}) case err != nil: return fmt.Errorf("failed to update mapping of index %s: %w", name, err) case !putResp.Acknowledged: