Problem/Motivation
When a string field (mapped to a keyword field in OpenSearch) contains a value exceeding 32,766 bytes, OpenSearch throws a max_bytes_length_exceeded_exception and the request fails with a 400 status code:
[error] Document contains at least one immense term in field="processed" (whose UTF8 encoding is longer than the max length 32766), all of which were skipped. Please correct the analyzer to not produce such terms. The prefix of the first immense term is: '...[redacted]...', original message: bytes can be at most 32766 in length; got 37582 max_bytes_length_exceeded_exception: bytes can be at most 32766 in length; got 37582 for id: entity:my_entity/123:und. Status code: 400
This limit is IndexWriter.MAX_TERM_LENGTH, a hard limit enforced by Lucene's engine. It applies to keyword fields because their values are indexed as a single term. Fulltext (text) fields are not affected since their content is tokenized into individual words.
In most cases this error indicates a field type misconfiguration: a field containing long text content is indexed as string (keyword) when it should be fulltext (text). However, regardless of root cause, the current behavior (a hard 400 error that aborts the rest of the bulk indexing request) is disruptive. The module could handle this gracefully by truncating the oversized value and logging a warning that guides the site administrator toward the correct fix.
Steps to reproduce
- Configure a Search API index with a field of type
string. - Index an entity where that field contains a value longer than 32,766 bytes.
- Observe a 400 error and indexing failure in the logs.
Proposed resolution
In IndexParamBuilder::buildFieldValues(), truncate string type values to MAX_TERM_BYTES (32,766) using mb_strcut() before indexing, to respect UTF-8 multibyte character boundaries. Log a warning when truncation occurs so site admins are informed and can correct the underlying field type configuration.
Note: TextValue instances (fulltext fields) do not need truncation since their content is tokenized by OpenSearch's analyzer.
Remaining tasks
- Submit initial PR.
User interface changes
None.
API changes
None.
Data model changes
None.
Issue fork search_api_opensearch-3576613
Show commands
Start within a Git clone of the project using the version control instructions.
Or, if you do not have SSH keys set up on git.drupalcode.org:
Comments
Comment #3
arlina commentedSubmitted a MR, changing status to "needs review".
Comment #4
kim.pepperThanks for your MR. This looks great.
I went to run a test-only pipeline to ensure the test fails currently in HEAD, and it got an error instead about an undefined constant IndexParamBuilder::MAX_TERM_BYTES. Could we just define a test only variable / const?
Comment #5
arlina commentedPR feedback resolved, changing back to needs review.
Comment #7
kim.pepperCommitted to 2.x and cherry-picked to 3.x. Thanks!