Skip to content

Sticky asset loader crashes when block className is an array #2996

Description

@pirate-bot

Summary

Rendering a block with an array-valued className can trigger a frontend fatal error while Otter checks whether the block uses sticky behavior.

Expected behavior: Block rendering continues when a block has an unexpected or malformed className attribute.

Actual behavior: Rendering terminates with TypeError: strpos(): Argument #1 ($haystack) must be of type string, array given.

Impact: The affected page cannot render until the triggering block data is avoided or corrected.

Customer context

  • Product / area: Otter Blocks sticky asset loading
  • Version: 3.0.12
  • Environment: WordPress 7.1; PHP 8.3.32; frontend request
  • Integration / third party: Theme JNews appears in the reported render stack
  • Reported error / symptom: TypeError: strpos(): Argument #1 ($haystack) must be of type string, array given
  • Impact: 3 occurrences across 1 site in the telemetry query window.

Reproduction notes

  1. In a WordPress frontend request with Otter active, render a block whose parsed attributes include className as an array.
  2. The global render_block callback reaches the sticky asset loader.
  3. In version 3.0.12, the reported strpos() TypeError is expected from the tagged code path.

Production reproduction is confirmed by telemetry; the source of the malformed attribute is not provided.

Diagnosis

Conclusion

Production telemetry identifies Registration::load_sticky() as the throwing frame in Otter Blocks 3.0.12. The tagged release invokes strpos() on block['attrs']['className'] after testing only for presence, so an array reaches a function that requires a string. This directly matches the captured TypeError. The source editor path normally serializes the sticky classes as a string, indicating the crash requires unexpected or malformed block attribute data, but the frontend handler lacks a safe boundary for it.

Where this likely occurs

  • inc/class-registration.phpRegistration::init() lines 103-113 registers Registration::load_sticky() on the global render_block filter at priority 900, making the handler run during frontend block rendering.
  • inc/class-registration.phpRegistration::load_sticky() lines 1115-1136; line 1120 checks only isset() before passing attrs.className to strpos().
  • Release v3.0.12 contains the equivalent call at inc/class-registration.phpRegistration::load_sticky() lines 978-1000, with the call at line 983, matching the telemetry location exactly.
  • inc/class-registration.phpRegistration::load_sticky() line 1120 traces by blame to commit 39d7d75ac (2022-07-22); the relevant expression remains unchanged between v3.0.12 and the inspected checkout.

Engineering notes

  • The telemetry marks this as product code rather than bundled Themeisle SDK code, so the issue routes to Codeinwp/otter-blocks.
  • src/blocks/plugins/sticky/index.jstoggleSticky() lines 22-35 and StickyExtension() lines 37-60 construct and save a space-delimited string for normal editor interactions. That workflow does not explain the array value, but it confirms the frontend path is exposed to block attributes that may originate outside this UI.
  • The captured trace runs through WordPress block rendering. WordPress core source was not present in the inspected workspace, so the parsed-block attribute shape beyond the telemetry evidence was not independently verified.

Test coverage status

No sticky-specific test files were found under src/blocks/test, and no PHP tests referencing load_sticky or o-sticky were found during inspection. Existing editor code was inspected, but no test covering non-string className input was located.

What to verify or explore next

  • Reproduce rendering a parsed block whose attrs.className is an array while the sticky render filter is active.
  • Run the relevant PHP test suite after adding or locating coverage for Registration::load_sticky().
  • Check whether imported content, reusable blocks, or third-party block transformations can persist an array-valued className attribute.

Unknowns / follow-up

  • The telemetry does not include the serialized block markup or identify the block that carried the array-valued attribute.
  • It is unknown whether the malformed attribute was authored by a third-party integration, imported content, or persisted historical data.

Confidence

Confidence: 98/100

Production telemetry records three frontend crashes on one site in Otter Blocks 3.0.12, and the tagged source passes attrs.className to PHP strpos() without checking that it is a string. The stack location and reported TypeError directly match that call.

Crash telemetry

Occurrences 3
Distinct sites 1
First seen 2026-08-22 12:36 UTC
Last seen 2026-08-23 22:40 UTC
Crash location product:inc/class-registration.php:983
Request context frontend
Inside Themeisle SDK no
Product versions 3.0.12
WP versions 7.1
PHP versions 8.3.32
SDK versions 3.3.58

Source: automated crash report — otter-blocks, fingerprint ad8f3634cd6915f569a5456ff8295b76
Generated by bug-report-triage (ID: bug-report-triage_6a8bde12ae2b84.43414214)

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions