I’ve been having a hard time figuring out an error that a client’s been getting in the Android and iOS apps for WordPress, but finally found the reason. The problem was that, when adding new posts with images, the post would be saved and the image would be uploaded and attached to the post, but the user would get an error and the app would locally store the post as a draft instead of recognizing that it’s actually published. The error from the Android app was:
org.xmlpull.v1.XmlPullParserException: unexpected type (position: TEXT Empty delimiter …@3:25 in java.io.InputStreamReader@43626400)
After a lot of debugging and Googling, I finally found a set of threads from the WP Android app forums and the wordpress.org forums that explained the problem. It turns out that the attach_uploads() function in the wp_xmlrpc_server class isn’t checking if $file->guid is valid before passing it to strpos(). If it’s empty, then PHP generates warning because of the invalid parameter. The Apache logs read:
[Thu May 24 15:26:14 2012] [warn] [client redacted] mod_fcgid: stderr: PHP Warning: strpos(): Empty delimiter in /var/www/vhosts/redacted/httpdocs/wp-includes/class-wp-xmlrpc-server.php on line 2470
If display_errors is turned on, that warning makes some XML-RPC clients freak out. There’s a Trac ticket for it, but right now the patch doesn’t fix the entire issue, and the ticket hasn’t been accepted yet.
The workaround is fairly simple, just turn display_errors off — which you’d want to do before moving to production anyway — but it’s still a pain in the ass to track down. Note that WP_DEBUG will try to enable display_errors even if your PHP config has it turned off by default, so make sure that’s disabled too.
While working on this I came across some useful generic advice on debugging XML-RPC problems in WordPress:
- Manually post requests via curl and view the raw output.
- Set $xmlrpc_logging = true in /xmlrpc.php and check xmlrpc.log. You may need to manually create xmlrpc.log depending on your permission settings. You may also need to temporarily edit logIO() to write it in a location inside your open_basedir path.
- Don’t use wp_die() or echo any output because that messes up the XML, which causes new errors. Instead, use set_transient() and view the output in the database.