Wp-calypso: Editor: Intermittent 'url' TypeError when uploading featured image

Created on 11 Oct 2017  路  6Comments  路  Source: Automattic/wp-calypso

Steps to reproduce

Update: See https://github.com/Automattic/wp-calypso/issues/18752#issuecomment-336053425 for better steps.

  1. Edit an existing post, or start a new one
  2. Type some stuff in the Visual editor (this may not be necessary, but seems to trigger the error more frequently)
  3. Drag and drop an image onto the sidebar's featured image dropzone
  4. Repeat those steps until you encounter the fatal error in the console: Uncaught TypeError: Parameter 'url' must be a string, not number
  5. It may take 10-30 times before it happens, but sometimes it happens more regularly. Try varying how much text you type into the editor, how many images you drag, which dropzone you drop them on, visual vs HTML tab, drag images that have already been uploaded, ones that haven't, etc.

If you want to catch the error during debugging, you can add the following snippet to the start of maxWidthPhotonishURL() in client/lib/post-normalizer/utils.js:

if ( 'string' !== typeof imageURL ) {
    debugger;
}

The imageURL that gets passed looks like the ID of a media library item, rather than its URL.

Stack trace from browser console after the error is thrown:

connectAdvanced.js:250 Uncaught TypeError: Parameter 'url' must be a string, not number
    at Url.parse (url.js:112)
    at Object.urlParse [as parse] (url.js:106)
    at maxWidthPhotonishURL (utils.js:81)
    at detectMedia (rule-content-detect-media.js:177)
    at eval (rule-with-content-dom.js:27)
    at arrayReduce (lodash.js:689)
    at reduce (lodash.js:9354)
    at withContentDOM (rule-with-content-dom.js:26)
    at eval (lodash.js:4954)
    at normalizePostForDisplay (utils.js:183)
    at eval (selectors.js:96)
    at memoized (lodash.js:10240)
    at memoizedSelector (index.js:156)
    at Function.eval [as mapToProps] (index.jsx:116)
    at mapToPropsProxy (wrapMapToProps.js:47)
    at handleNewState (selectorFactory.js:56)
    at handleSubsequentCalls (selectorFactory.js:73)
    at pureFinalPropsSelector (selectorFactory.js:78)
    at Object.runComponentSelector [as run] (connectAdvanced.js:35)
    at Connect.onStateChange (connectAdvanced.js:208)
    at Object.notify (Subscription.js:27)
    at Subscription.notifyNestedSubs (Subscription.js:63)
    at Connect.onStateChange (connectAdvanced.js:211)
    at Object.notify (Subscription.js:27)
    at Subscription.notifyNestedSubs (Subscription.js:63)
    at Connect.notifyNestedSubsOnComponentDidUpdate (connectAdvanced.js:225)
    at measureLifeCyclePerf (ReactCompositeComponent.js:75)
    at eval (ReactCompositeComponent.js:729)
    at CallbackQueue.notifyAll (CallbackQueue.js:76)
    at ReactReconcileTransaction.close (ReactReconcileTransaction.js:80)
    at ReactReconcileTransaction.closeAll (Transaction.js:206)
    at ReactReconcileTransaction.perform (Transaction.js:153)
    at ReactUpdatesFlushTransaction.perform (Transaction.js:140)
    at ReactUpdatesFlushTransaction.perform (ReactUpdates.js:89)
    at Object.flushBatchedUpdates (ReactUpdates.js:172)
    at ReactDefaultBatchingStrategyTransaction.closeAll (Transaction.js:206)
    at ReactDefaultBatchingStrategyTransaction.perform (Transaction.js:153)
    at Object.batchedUpdates (ReactDefaultBatchingStrategy.js:62)
    at Object.enqueueUpdate (ReactUpdates.js:200)
    at enqueueUpdate (ReactUpdateQueue.js:24)
    at Object.enqueueSetState (ReactUpdateQueue.js:209)
    at Connect.ReactComponent.setState (ReactComponent.js:63)
    at Connect.onStateChange (connectAdvanced.js:214)
    at eval (createStore.js:132)
    at Array.forEach (<anonymous>)
    at Object.dispatch (createStore.js:131)
    at dispatch (<anonymous>:2:31875)
    at eval (middleware.js:59)
    at eval (middleware.js:74)
    at eval (middleware.js:286)
    at eval (middleware.js:116)
    at eval (middleware.js:72)
    at eval (middleware.js:253)
    at Object.eval [as handleAction] (wpcom-api-middleware.js:97)
    at eval (extensions-middleware.js:123)
    at eval (wpcom-api-middleware.js:97)
    at Object.eval [as dispatch] (index.js:12)
    at dispatch (index.js:115)
    at Object.eval [as receivePost] (bindActionCreators.js:14)
    at Object.onSaveSuccess (post-editor.jsx:1174)
    at Object.onSaveDraftSuccess (post-editor.jsx:1006)
    at Object.eval (post-editor.jsx:786)
    at eval (actions.js:433)
    at eval (send-request.js:104)
    at XMLHttpRequest.xhrOnLoad (index.js:177)
    at resolve (index.js:547)
    at onmessage (index.js:510)

Call stack inside debugger at moment error is thrown:

render (connectAdvanced.js:250)
(anonymous) (ReactCompositeComponent.js:796)
measureLifeCyclePerf (ReactCompositeComponent.js:75)
_renderValidatedComponentWithoutOwnerOrContext (ReactCompositeComponent.js:795)
_renderValidatedComponent (ReactCompositeComponent.js:822)
_updateRenderedComponent (ReactCompositeComponent.js:746)
_performComponentUpdate (ReactCompositeComponent.js:724)
updateComponent (ReactCompositeComponent.js:645)
performUpdateIfNecessary (ReactCompositeComponent.js:561)
performUpdateIfNecessary (ReactReconciler.js:157)
runBatchedUpdates (ReactUpdates.js:150)
perform (Transaction.js:140)
perform (Transaction.js:140)
perform (ReactUpdates.js:89)
flushBatchedUpdates (ReactUpdates.js:172)
close (ReactUpdates.js:47)
closeAll (Transaction.js:206)
perform (Transaction.js:153)
perform (ReactUpdates.js:89)
flushBatchedUpdates (ReactUpdates.js:172)
closeAll (Transaction.js:206)
perform (Transaction.js:153)
batchedUpdates (ReactDefaultBatchingStrategy.js:62)
enqueueUpdate (ReactUpdates.js:200)
enqueueUpdate (ReactUpdateQueue.js:24)
enqueueSetState (ReactUpdateQueue.js:209)
ReactComponent.setState (ReactComponent.js:63)
onStateChange (connectAdvanced.js:214)
(anonymous) (createStore.js:132)
dispatch (createStore.js:131)
dispatch (VM22579:2)
(anonymous) (middleware.js:59)
(anonymous) (middleware.js:74)
(anonymous) (middleware.js:286)
(anonymous) (middleware.js:116)
(anonymous) (middleware.js:72)
(anonymous) (middleware.js:253)
(anonymous) (wpcom-api-middleware.js:97)
(anonymous) (extensions-middleware.js:123)
(anonymous) (wpcom-api-middleware.js:97)
(anonymous) (index.js:12)
dispatch (index.js:115)
(anonymous) (bindActionCreators.js:14)
onSaveSuccess (post-editor.jsx:1174)
onSaveDraftSuccess (post-editor.jsx:1006)
(anonymous) (post-editor.jsx:786)
(anonymous) (actions.js:433)
(anonymous) (send-request.js:104)
xhrOnLoad (index.js:177)
resolve (index.js:547)
onmessage (index.js:510)
postMessage (async)
sendMessage ((index):351)
(anonymous) ((index):339)
i (??/wp-includes/js/jquery/jquery.js,/wp-content/js/postmessage.js?m=1377267974j:2)
fireWith (??/wp-includes/js/jquery/jquery.js,/wp-content/js/postmessage.js?m=1377267974j:2)
y (??/wp-includes/js/jquery/jquery.js,/wp-content/js/postmessage.js?m=1377267974j:4)
c (??/wp-includes/js/jquery/jquery.js,/wp-content/js/postmessage.js?m=1377267974j:4)
XMLHttpRequest.send (async)
send (??/wp-includes/js/jquery/jquery.js,/wp-content/js/postmessage.js?m=1377267974j:4)
ajax (??/wp-includes/js/jquery/jquery.js,/wp-content/js/postmessage.js?m=1377267974j:4)
receiveMessage ((index):271)
(anonymous) ((index):277)
dispatch (??/wp-includes/js/jquery/jquery.js,/wp-content/js/postmessage.js?m=1377267974j:3)
r.handle (??/wp-includes/js/jquery/jquery.js,/wp-content/js/postmessage.js?m=1377267974j:3)
postMessage (async)
submitRequest (index.js:225)
request (index.js:202)
(anonymous) (index.js:128)
(anonymous) (index.js:67)
request (index.js:353)
request (support.js:89)
request (index.js:100)
request (guest-sandbox-ticket.js:66)
sendRequest (send-request.js:102)
Req.post.Req.put (request.js:69)
update (site.post.js:224)
saveEdited (actions.js:412)
autosave (actions.js:258)
autosave (post-editor.jsx:792)
invokeFunc (lodash.js:10024)
trailingEdge (lodash.js:10071)
timerExpired (lodash.js:10059)
setTimeout (async)
setTimeout (lodash.js:6344)
leadingEdge (lodash.js:10032)
debounced (lodash.js:10099)
invokeFunc (lodash.js:10024)
trailingEdge (lodash.js:10071)
timerExpired (lodash.js:10059)
setTimeout (async)
setTimeout (lodash.js:6344)
timerExpired (lodash.js:10062)
setTimeout (async)
setTimeout (lodash.js:6344)
leadingEdge (lodash.js:10032)
debounced (lodash.js:10099)
onEditorContentChange (post-editor.jsx:727)
fire (tinymce.js:30773)
fire (tinymce.js:31013)
add (tinymce.js:25600)
addNonTypingUndoLevel (tinymce.js:25396)
(anonymous) (tinymce.js:25480)
fire (tinymce.js:30773)
fire (tinymce.js:31013)
delegate (tinymce.js:37859)
executeHandlers (tinymce.js:1184)
defaultNativeHandler (tinymce.js:1211)

Browser / OS version

Chrome 61

Editor [Pri] Low [Type] Bug

Most helpful comment

@lancewillett a workaround has been implemented for the issue in #18770, until a better solution can be considered and implemented.

This is a bit of an edge-case and it's not triggered very often. With the workaround there shouldn't be any chance of losing user content, except the currently uploading Featured Image. If the issue happens, the Featured Image that is currently being uploaded will get reverted to the previous state, either no Featured Image or the previous one that was set.

Proper fix will require blocking the save functionality while an upload is active or make the save a bit smarter and modular ( to save only the content or only the featured image for example ), so it can save things independently of each-other.

We're still in early talks on what will the better solution be and what implementation difficulties may arise from either solution.

All 6 comments

(updated) I think I found a way to trigger it:

  1. Add a featured image
  2. Type something in the editor and save the post
  3. Type something in the post again, so you see the Save button light up, don't save.
  4. Drag a new featured image
  5. Immediately when it starts uploading, click Save to save the post draft
  6. The bug should trigger

Yup, that seems to reproduce it consistently for me too, good job!

Hi @iandunn Are you working to fix this one?

@lancewillett a workaround has been implemented for the issue in #18770, until a better solution can be considered and implemented.

This is a bit of an edge-case and it's not triggered very often. With the workaround there shouldn't be any chance of losing user content, except the currently uploading Featured Image. If the issue happens, the Featured Image that is currently being uploaded will get reverted to the previous state, either no Featured Image or the previous one that was set.

Proper fix will require blocking the save functionality while an upload is active or make the save a bit smarter and modular ( to save only the content or only the featured image for example ), so it can save things independently of each-other.

We're still in early talks on what will the better solution be and what implementation difficulties may arise from either solution.

Do we need to keep this open considering the workaround is in place? If we're keeping it open can I please assign it to someone?

I'm happy to close it. We can re-open later if work continues.

Was this page helpful?
0 / 5 - 0 ratings