Skip to content

REST API: Normalize non-integer attachment filesize metadata#12611

Closed
apermo wants to merge 28 commits into
WordPress:trunkfrom
apermo:trac-65670-attachment-filesize-typeerror
Closed

REST API: Normalize non-integer attachment filesize metadata#12611
apermo wants to merge 28 commits into
WordPress:trunkfrom
apermo:trac-65670-attachment-filesize-typeerror

Conversation

@apermo

@apermo apermo commented Jul 20, 2026

Copy link
Copy Markdown

Trac ticket

https://core.trac.wordpress.org/ticket/65670

Problem

WP_REST_Attachments_Controller::get_attachment_filesize() (new in 7.0.0) returns the filesize value from attachment metadata verbatim against a strict ?int return type. Attachment metadata is untyped postmeta, so a non-numeric string value throws a fatal TypeError when the media endpoint is requested:

TypeError: WP_REST_Attachments_Controller::get_attachment_filesize():
Return value must be of type ?int, string returned

A numeric string only survives because the file has no strict_types declaration (coercion). A non-numeric one fatals.

Plugins populate filesize from remote storage API responses — e.g. the Google Drive fileSize field (returned as a string) via WP Media Folder, and the equivalent Dropbox/OneDrive addons — so this occurs on real sites.

Fix

Only return the stored value when it is numeric, cast to int; otherwise fall through to recompute the size from the file via wp_filesize() (which always casts to int), returning null if unavailable. This matches the 'type' => 'integer' REST schema.

Testing

Two regression tests added to tests/phpunit/tests/rest-api/rest-attachments-controller.php:

  • numeric-string filesize meta → normalized to int in the response;
  • non-numeric filesize meta → no fatal, falls back to the real file size.

The non-numeric test reproduces the reported TypeError against unpatched trunk (red), and passes with the fix (green).

Disclosure

Claude (Anthropic) assisted in diagnosing the root cause and drafting the patch and tests. I reviewed the change, verified the red/green test behavior locally, and take responsibility for it.

Attachment metadata is untyped, so `filesize` can be stored as a
string (for example, plugins that populate it from a remote storage
API response such as the Google Drive `fileSize` field, which the
API returns as a string). Returning it verbatim violated the `?int`
return type of
`WP_REST_Attachments_Controller::get_attachment_filesize()` and
caused a fatal TypeError for non-numeric values.

Only return the stored value when numeric, casting to int; otherwise
fall through to recompute the size from the file via wp_filesize().

Fixes https://core.trac.wordpress.org/ticket/65670

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@github-actions

github-actions Bot commented Jul 20, 2026

Copy link
Copy Markdown

The following accounts have interacted with this PR and/or linked issues. I will continue to update these lists as activity occurs. You can also manually ask me to refresh this list by adding the props-bot label.

Core Committers: Use this line as a base for the props when committing in SVN:

Props apermo, westonruter, xate, mukesh27.

To understand the WordPress project's expectations around crediting contributors, please review the Contributor Attribution page in the Core Handbook.

@apermo

apermo commented Jul 20, 2026

Copy link
Copy Markdown
Author

@westonruter would you be able to review this? It fixes a fatal TypeError in get_attachment_filesize() (new in 7.0.0) when filesize attachment metadata is stored as a non-numeric string — which happens on sites using plugins that populate it from remote storage APIs (e.g. the Google Drive fileSize string via WP Media Folder). Trac: https://core.trac.wordpress.org/ticket/65670

@apermo

apermo commented Jul 20, 2026

Copy link
Copy Markdown
Author

@westonruter Would you be so kind to have a look at it? Thanks :)

@xateman xateman left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good 👍

@github-actions

Copy link
Copy Markdown

Test using WordPress Playground

The changes in this pull request can previewed and tested using a WordPress Playground instance.

WordPress Playground is an experimental project that creates a full WordPress instance entirely within the browser.

Some things to be aware of

  • All changes will be lost when closing a tab with a Playground instance.
  • All changes will be lost when refreshing the page.
  • A fresh instance is created each time the link below is clicked.
  • Every time this pull request is updated, a new ZIP file containing all changes is created. If changes are not reflected in the Playground instance,
    it's possible that the most recent build failed, or has not completed. Check the list of workflow runs to be sure.

For more details about these limitations and more, check out the Limitations page in the WordPress Playground documentation.

Test this pull request with WordPress Playground.

Comment thread src/wp-includes/rest-api/endpoints/class-wp-rest-attachments-controller.php Outdated
apermo and others added 2 commits July 20, 2026 13:41
Shorten the inline comment in get_attachment_filesize() to the
essential rationale, per PR review feedback.

See https://core.trac.wordpress.org/ticket/65670

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings July 21, 2026 02:58

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR fixes a REST API fatal error in WP_REST_Attachments_Controller::get_attachment_filesize() by ensuring attachment filesize metadata (which is untyped postmeta) is normalized to an integer (or recomputed) before being returned under a strict ?int return type.

Changes:

  • Normalize numeric filesize metadata to an int, and fall back to recomputing the file size when metadata is not usable.
  • Add REST API regression tests covering numeric-string and non-numeric filesize metadata cases.
  • Add an extra sanity assertion in an existing attachment REST test to ensure the factory returns an integer attachment ID.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.

File Description
tests/phpunit/tests/rest-api/rest-attachments-controller.php Adds regression tests validating filesize normalization and non-numeric recovery behavior.
src/wp-includes/rest-api/endpoints/class-wp-rest-attachments-controller.php Hardens get_attachment_filesize() by validating/casting stored metadata before returning it.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/wp-includes/rest-api/endpoints/class-wp-rest-attachments-controller.php Outdated
Comment thread src/wp-includes/rest-api/endpoints/class-wp-rest-attachments-controller.php Outdated
Comment thread tests/phpunit/tests/rest-api/rest-attachments-controller.php
Refine the filesize metadata guard per PR review: accept only a
positive integer (an int or a digit-only string), rather than any
numeric value. This avoids silently truncating float strings such
as '123.4' via the int cast, and rejects zero and negative values,
falling through to recompute the size from the file in those cases.

Also document the method's positive-integer return with a
@phpstan-return non-negative-int|null annotation.

See https://core.trac.wordpress.org/ticket/65670

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings July 21, 2026 06:32

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.

Comment thread src/wp-includes/rest-api/endpoints/class-wp-rest-attachments-controller.php Outdated
Comment thread tests/phpunit/tests/rest-api/rest-attachments-controller.php
Attachment metadata is untyped, so `filesize` may be a float, bool
or other non-string scalar. Passing such a value to ctype_digit()
is fragile (deprecated in PHP 8.1+), so guard the call with
is_string(); non-string scalars now fall through to recompute the
size from the file.

Extend the invalid-value data provider with float and boolean cases.

See https://core.trac.wordpress.org/ticket/65670

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings July 21, 2026 06:39

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 2 out of 2 changed files in this pull request and generated no new comments.

Copilot AI review requested due to automatic review settings July 21, 2026 07:23

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I fixed the typing of this function as otherwise get_attachment_filesize() would not be guaranteed to return a non-negative-int. This would warrant additional tests to ensure negative values get increased to zero.

Could there be any reason any plugin would filter pre_wp_filesize or wp_filesize to be negative?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Besides the obvious "Developer did a bad job, or had some quirky idea"?

I don't think so, but that alone is already bad enough.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No technically legitimate reason, but definitely a reason.

Comment thread src/wp-includes/rest-api/endpoints/class-wp-rest-attachments-controller.php Outdated

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 4 out of 4 changed files in this pull request and generated no new comments.

Copilot AI review requested due to automatic review settings July 21, 2026 20:14

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 4 out of 4 changed files in this pull request and generated 1 comment.

Comments suppressed due to low confidence (2)

src/wp-includes/rest-api/endpoints/class-wp-rest-attachments-controller.php:2369

  • is_numeric( $meta['filesize'] ) allows non-integer numeric strings (e.g. '123.4', '1e3') and floats; casting those to (int) can silently change the stored value. Since filesize is a byte count (integer per REST schema), it’s safer to only accept a positive int or a digit-only string and otherwise fall back to wp_filesize().
		if ( isset( $meta['filesize'] ) && is_numeric( $meta['filesize'] ) && $meta['filesize'] > 0 ) {
			return (int) $meta['filesize'];
		}

tests/phpunit/tests/rest-api/rest-attachments-controller.php:1108

  • To prevent regressions where non-integer numeric values get truncated (or where non-string scalars would hit ctype_digit()), consider adding '123.4', '1e3', and 123.0 to the invalid filesize provider so the test asserts the response falls back to the actual on-disk file size.
		return array(
			'non-numeric string'      => array( 'corrupt' ),
			'boolean'                 => array( true ),
			'zero'                    => array( 0 ),
			'zero string'             => array( '0' ),
			'negative integer'        => array( -5 ),

Comment thread tests/phpunit/tests/rest-api/rest-attachments-controller.php
westonruter and others added 9 commits July 21, 2026 13:28
State the zero-or-greater guarantee the same way in the function docblock
as in the wp_filesize hook docblock, rather than phrasing it two different
ways in one function.

Describe the pre_wp_filesize short-circuit as accepting a non-negative
number, since a non-negative numeric string bypasses the filesize call too.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Cover a negative int, a negative numeric string, and a negative float,
since the filtered value is now normalized with is_numeric() rather than
is_int() and each of those types reaches the sign check differently.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings July 21, 2026 21:04
$schema['properties']['filesize'] = array(
'description' => __( 'Attachment file size in bytes.' ),
'type' => 'integer',
'type' => array( 'integer', 'null' ),

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Claude pointed out that null could be returned by the endpoint.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 4 out of 4 changed files in this pull request and generated 2 comments.

Comments suppressed due to low confidence (2)

src/wp-includes/rest-api/endpoints/class-wp-rest-attachments-controller.php:2369

  • get_attachment_filesize() currently treats any positive is_numeric() metadata value as valid and then (int)-casts it. This accepts values like '123.4' and '1e3', which get silently truncated/normalized (123 and 1000) even though a byte size should be an integer. That can surface an incorrect filesize in the REST response rather than falling back to wp_filesize().
		if ( isset( $meta['filesize'] ) && is_numeric( $meta['filesize'] ) && $meta['filesize'] > 0 ) {
			return (int) $meta['filesize'];
		}

tests/phpunit/tests/rest-api/rest-attachments-controller.php:1062

  • This docblock says invalid filesize values should not cause a "silently truncated size", but the data_valid_filesize_meta() provider above explicitly asserts truncation/normalization for values like '123.4'. The documentation here should be updated to match the behavior under test.
	 * Ensures a `filesize` metadata value that is not a positive integer does
	 * not cause a fatal TypeError or a silently truncated size, falling back to
	 * the actual file size instead.

Comment thread tests/phpunit/tests/rest-api/rest-attachments-controller.php Outdated
Comment thread src/wp-includes/functions.php
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings July 21, 2026 21:12

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 4 out of 4 changed files in this pull request and generated 1 comment.

Comments suppressed due to low confidence (2)

src/wp-includes/rest-api/endpoints/class-wp-rest-attachments-controller.php:2369

  • is_numeric( $meta['filesize'] ) will treat values like '123.4' and '1e3' as valid, and casting those to (int) silently changes the stored value (truncation / notation parsing). Since filesize represents a byte count, it should only accept integer values (int, integer-like float with no fractional part, or digit-only string) and otherwise fall back to wp_filesize().
		if ( isset( $meta['filesize'] ) && is_numeric( $meta['filesize'] ) && $meta['filesize'] > 0 ) {
			return (int) $meta['filesize'];
		}

tests/phpunit/tests/rest-api/rest-attachments-controller.php:1056

  • data_valid_filesize_meta() currently treats float/scientific-notation strings as “valid” and asserts truncation via (int) casting. If filesize is meant to be an integer byte-count, these should be treated as invalid metadata and the controller should fall back to the real file size instead (avoids silent truncation).
		return array(
			'integer string'      => array( '123456', 123456 ),
			'float string'        => array( '123.4', 123 ),
			'scientific notation' => array( '1e3', 1000 ),
			'float'               => array( 123.0, 123 ),
		);

Comment thread tests/phpunit/tests/rest-api/rest-attachments-controller.php
pento pushed a commit that referenced this pull request Jul 21, 2026
…nt`.

A negative file size is clearly impossible, and the return value of 0 is already documented as being the error case.

* Values filtered by `pre_wp_filesize` and `wp_filesize` are cast to `int` if they are numeric.
* Non-numeric values returned by the `wp_filesize` filter are discarded in favor of zero.
* Negative values filtered by the `pre_wp_filesize` filter are treated the same as `null` (and do not short-circuit).
* Negative values returned by the `wp_filesize` filter are clamped to be at least zero.

Developed as part of #12611.
Follow-up to r52837, r52932.

Props westonruter, apermo.
See #65670, #64898.


git-svn-id: https://develop.svn.wordpress.org/trunk@62813 602fd350-edb4-49c9-b593-d223f7449a82
markjaquith pushed a commit to markjaquith/WordPress that referenced this pull request Jul 21, 2026
…nt`.

A negative file size is clearly impossible, and the return value of 0 is already documented as being the error case.

* Values filtered by `pre_wp_filesize` and `wp_filesize` are cast to `int` if they are numeric.
* Non-numeric values returned by the `wp_filesize` filter are discarded in favor of zero.
* Negative values filtered by the `pre_wp_filesize` filter are treated the same as `null` (and do not short-circuit).
* Negative values returned by the `wp_filesize` filter are clamped to be at least zero.

Developed as part of WordPress/wordpress-develop#12611.
Follow-up to r52837, r52932.

Props westonruter, apermo.
See #65670, #64898.

Built from https://develop.svn.wordpress.org/trunk@62813


git-svn-id: http://core.svn.wordpress.org/trunk@62093 1a063a9b-81f0-0310-95a4-ce76da25c4cd
pento pushed a commit that referenced this pull request Jul 21, 2026
* The return value of the `WP_REST_Attachments_Controller::get_attachment_filesize()` method is narrowed from `int|null` to `non-negative-int|null`.
* The stored `filesize` attachment metadata is only returned if it is a numeric value and is greater than zero; it is cast to an `int`, preventing a `TypeError` if a non-numeric string was stored in metadata.
* The `filesize` property of the attachments endpoint adds `null` as a possible value in addition to `integer`.

Developed in #12611.
Follow-up to r62813, r61703.

Props apermo, westonruter, xate, mukesh27.
Fixes #65670.


git-svn-id: https://develop.svn.wordpress.org/trunk@62815 602fd350-edb4-49c9-b593-d223f7449a82
@github-actions

Copy link
Copy Markdown

A commit was made that fixes the Trac ticket referenced in the description of this pull request.

SVN changeset: 62815
GitHub commit: 128db3c

This PR will be closed, but please confirm the accuracy of this and reopen if there is more work to be done.

@github-actions github-actions Bot closed this Jul 21, 2026
markjaquith pushed a commit to markjaquith/WordPress that referenced this pull request Jul 21, 2026
* The return value of the `WP_REST_Attachments_Controller::get_attachment_filesize()` method is narrowed from `int|null` to `non-negative-int|null`.
* The stored `filesize` attachment metadata is only returned if it is a numeric value and is greater than zero; it is cast to an `int`, preventing a `TypeError` if a non-numeric string was stored in metadata.
* The `filesize` property of the attachments endpoint adds `null` as a possible value in addition to `integer`.

Developed in WordPress/wordpress-develop#12611.
Follow-up to r62813, r61703.

Props apermo, westonruter, xate, mukesh27.
Fixes #65670.

Built from https://develop.svn.wordpress.org/trunk@62815


git-svn-id: http://core.svn.wordpress.org/trunk@62095 1a063a9b-81f0-0310-95a4-ce76da25c4cd
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants