diff --git a/src/wp-admin/includes/template.php b/src/wp-admin/includes/template.php
index 2eaf67454394e..ba4ecdc6d3ed4 100644
--- a/src/wp-admin/includes/template.php
+++ b/src/wp-admin/includes/template.php
@@ -2297,6 +2297,10 @@ function _post_states( $post, $display = true ) {
 function get_post_states( $post ) {
 	$post_states = array();
 
+	if ( ! $post instanceof WP_Post ) {
+		return $post_states;
+	}
+
 	if ( isset( $_REQUEST['post_status'] ) ) {
 		$post_status = $_REQUEST['post_status'];
 	} else {
diff --git a/src/wp-includes/nav-menu.php b/src/wp-includes/nav-menu.php
index 83a67cfe2a800..dc6de5c70c662 100644
--- a/src/wp-includes/nav-menu.php
+++ b/src/wp-includes/nav-menu.php
@@ -875,10 +875,12 @@ function wp_setup_nav_menu_item( $menu_item ) {
 					$menu_item->type_label = $object->labels->singular_name;
 					// Denote post states for special pages (only in the admin).
 					if ( function_exists( 'get_post_states' ) ) {
-						$menu_post   = get_post( $menu_item->object_id );
-						$post_states = get_post_states( $menu_post );
-						if ( $post_states ) {
-							$menu_item->type_label = wp_strip_all_tags( implode( ', ', $post_states ) );
+						$menu_post = get_post( $menu_item->object_id );
+						if ( $menu_post instanceof WP_Post ) {
+							$post_states = get_post_states( $menu_post );
+							if ( $post_states ) {
+								$menu_item->type_label = wp_strip_all_tags( implode( ', ', $post_states ) );
+							}
 						}
 					}
 				} else {
diff --git a/tests/phpunit/tests/admin/includesTemplate.php b/tests/phpunit/tests/admin/includesTemplate.php
index 909aff217a583..436659179dd26 100644
--- a/tests/phpunit/tests/admin/includesTemplate.php
+++ b/tests/phpunit/tests/admin/includesTemplate.php
@@ -494,4 +494,21 @@ public function test_wp_add_dashboard_widget() {
 		// This doesn't actually get removed due to the invalid priority.
 		remove_meta_box( 'dashboard2', 'dashboard', 'normal' );
 	}
+
+	/**
+	 * Tests that get_post_states() handles a null value gracefully.
+	 *
+	 * This can happen when get_post() returns null (e.g., when a post
+	 * doesn't exist) and that result is passed to get_post_states()
+	 * without being checked first.
+	 *
+	 * @ticket 58932
+	 *
+	 * @covers ::get_post_states
+	 */
+	public function test_get_post_states_with_null_returns_empty_array() {
+		$result = get_post_states( null );
+		$this->assertIsArray( $result, 'get_post_states() should return an array when passed null.' );
+		$this->assertEmpty( $result, 'get_post_states() should return an empty array when passed null.' );
+	}
 }
