Skip to content

Fix: Add missing _uploadErrored method with onUploadError lifecycle hook#214

Merged
grantcopley merged 6 commits into
nextfrom
copilot/fix-upload-errored-method
Oct 10, 2025
Merged

Fix: Add missing _uploadErrored method with onUploadError lifecycle hook#214
grantcopley merged 6 commits into
nextfrom
copilot/fix-upload-errored-method

Conversation

Copy link
Copy Markdown
Contributor

Copilot AI commented Oct 9, 2025

Problem

When file uploads encountered errors (HTTP non-2xx responses), CBWire was throwing a CBWIREException:

Type: CBWIREException
Message: The method '_uploadErrored' does not exist.

This occurred because the JavaScript code in includes/js/livewire.js was calling a non-existent method when upload errors occurred:

this.component.$wire.call("_uploadErrored", name, errors, this.uploadBag.first(name).multiple);

Solution

This PR adds the missing _uploadErrored() method to Component.cfc and implements a new onUploadError() lifecycle hook that allows developers to handle upload errors in their components.

Implementation

The new method follows the same pattern as other lifecycle methods (onHydrate, onUpdate) and upload methods (_startUpload, _finishUpload):

function _uploadErrored( prop, errors, multiple ) {
    // Dispatch the upload errored event
    dispatchSelf(
        event="upload:errored",
        params=[
            "name"=arguments.prop
        ]
    );
    // Check if the component has an onUploadError method and invoke it
    if ( structKeyExists( this, "onUploadError" ) ) {
        invoke( this, "onUploadError", { 
            property: arguments.prop,
            errors: arguments.errors,
            multiple: arguments.multiple
        } );
    }
}

The method dispatches the upload:errored event to the JavaScript listener, which triggers the error callback handler, and optionally invokes the component's onUploadError() method if defined.

Usage

Developers can now handle upload errors by defining an onUploadError() method in their CBWIRE components:

component extends="cbwire.models.Component" {
    
    data = {
        "uploadFailed": false,
        "errorMessage": ""
    };
    
    function onUploadError( property, errors, multiple ) {
        data.uploadFailed = true;
        data.errorMessage = "Upload failed for " & arguments.property;
        // errors contains the server response if status was 422
        // multiple indicates if this was a multi-file upload
    }
}

Parameters

The lifecycle method receives three parameters with complete error context:

  • property: The property name for the file input
  • errors: The error response from the server (null if not a 422 response)
  • multiple: Boolean indicating if multiple files are being uploaded

Tests

Added comprehensive test coverage:

  • Test component with onUploadError() implementation
  • Test spec verifying the method is called correctly
  • Tests confirming all parameters are passed through

Related Issue

Fixes the CBWIREException error that occurred when file uploads failed.

Module version affected: 4.1.5+

Fixes #178

Original prompt

This section details on the original issue you should resolve

<issue_title>The method '_uploadErrored' does not exist.</issue_title>
<issue_description>CBWire is returning an error after trying to upload an image.

In the file modules/cbwire/includes/js/livewire.js a non-existent method _uploadErrored is called:

this.component.$wire.call("_uploadErrored", name, errors, this.uploadBag.first(name).multiple);

Type:        	CBWIREException
Message:	The method '_uploadErrored' does not exist.

It happens sometimes.

cbwire module version: 4.1.5

</issue_description>

<agent_instructions>Look how we are firing other lifecycle methods like onUpdate() and onHydrate.</agent_instructions>

Comments on the Issue (you are @copilot in this section)

@grantcopley @linuxonrails Thanks for reporting this. There does seem to be a missing `_uploadErrored` function that Livewire is sending but CBWIRE doesn't have. Could you post here the payload that Livewire is sending to your server when it's trying to call the uploadErrored function? You can find this in your browser's dev tools under the XHR tab. @grantcopley I wanted to bounce an idea off of you. When an error occurs during upload, Livewire fires off another server request to a method called `_uploadErrored`, which currently doesn't exist and is why this ticket is here. I'm thinking from the `_uploadErrored` call to look for a `onUploadError()` method on the CBWIRE component and if it exists, fire that. Otherwise, do nothing.

Thoughts?</comment_new>
<comment_new>@grantcopley
Unfortunately it doesn't look like Livewire can send what the error actually is, but we can at least fire the lifecycle method. We will need to define the _uploadErrored() method on Component.cfc and then check for the existance of onUploadError() there.</comment_new>

Fixes #178


✨ Let Copilot coding agent set things up for you — coding agent works faster and does higher quality work when set up for your repo.

Copilot AI and others added 3 commits October 9, 2025 21:53
Co-authored-by: grantcopley <1197835+grantcopley@users.noreply.github.com>
Co-authored-by: grantcopley <1197835+grantcopley@users.noreply.github.com>
Co-authored-by: grantcopley <1197835+grantcopley@users.noreply.github.com>
Copilot AI changed the title [WIP] Fix missing _uploadErrored method in CBWire Fix: Add missing _uploadErrored method with onUploadError lifecycle hook Oct 9, 2025
Copilot AI requested a review from grantcopley October 9, 2025 22:02
@grantcopley grantcopley marked this pull request as ready for review October 10, 2025 14:26
Comment thread models/Component.cfc Outdated
// Check if the component has an onUploadError method and invoke it
if ( structKeyExists( this, "onUploadError" ) ) {
invoke( this, "onUploadError", {
name: arguments.prop,
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

@copilot I'd like to change the name argument to instead be property

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Changed the parameter from name to property in the onUploadError lifecycle method (commit 8e4e2d9).

Co-authored-by: grantcopley <1197835+grantcopley@users.noreply.github.com>
@grantcopley
Copy link
Copy Markdown
Collaborator

@copilot Can you check livewire.js and look to see if when an error does occur during file upload, are we suppose to return a certain payload with the error information?

Co-authored-by: grantcopley <1197835+grantcopley@users.noreply.github.com>
Copy link
Copy Markdown
Contributor Author

Copilot AI commented Oct 10, 2025

@copilot Can you check livewire.js and look to see if when an error does occur during file upload, are we suppose to return a certain payload with the error information?

Yes, the JavaScript has a listener for upload:errored event that triggers markUploadErrored() to handle the error callback. I've updated _uploadErrored() to dispatch this event (commit 8d88fc3), matching the pattern used by _startUpload (dispatches upload:generatedSignedUrl) and _finishUpload (dispatches upload:finished).

@grantcopley
Copy link
Copy Markdown
Collaborator

@copilot One final thing, fully document the feature here in a comment where I can paste it into our documentation site please.

Copy link
Copy Markdown
Contributor Author

Copilot AI commented Oct 10, 2025

@copilot One final thing, fully document the feature here in a comment where I can paste it into our documentation site please.

Here's the complete documentation for the onUploadError lifecycle hook:


onUploadError Lifecycle Hook

The onUploadError() lifecycle hook is automatically called when a file upload encounters an error (any HTTP response with a non-2xx status code). This allows you to handle upload failures gracefully in your CBWIRE components.

Method Signature

function onUploadError( property, errors, multiple )

Parameters

Parameter Type Description
property string The name of the data property associated with the file input
errors any The error response from the server. Will be null unless the HTTP status is 422, in which case it contains the response body
multiple boolean Indicates whether multiple files were being uploaded (true) or a single file (false)

Usage Example

component extends="cbwire.models.Component" {
    
    data = {
        "photo": "",
        "uploadFailed": false,
        "errorMessage": ""
    };
    
    function onUploadError( property, errors, multiple ) {
        // Set error state
        data.uploadFailed = true;
        
        // Create user-friendly error message
        data.errorMessage = "Failed to upload " & ( multiple ? "files" : "file" ) & " for " & property;
        
        // Log the error for debugging
        if ( !isNull( errors ) ) {
            writeLog( type="error", text="Upload error for #property#: #serializeJSON(errors)#" );
        }
        
        // You could also dispatch events, send notifications, etc.
    }
}

Template Example

<cfoutput>
    <div>
        <input type="file" wire:model="photo">
        
        <cfif data.uploadFailed>
            <div class="alert alert-danger">
                #data.errorMessage#
            </div>
        </cfif>
    </div>
</cfoutput>

When It's Called

The onUploadError() hook is triggered when:

  • The upload server returns any HTTP status code outside the 2xx range (200-299)
  • Network errors occur during upload
  • The server is unreachable
  • Any other upload failure scenario

Error Information

The errors parameter provides different information based on the HTTP status:

  • 422 (Unprocessable Entity): Contains the full response body (typically validation errors)
  • Other error codes: Will be null

You can check the response status in your server logs or implement custom error handling based on your application's needs.

Common Use Cases

  1. Display user-friendly error messages

    function onUploadError( property, errors, multiple ) {
        data.errorMessage = "Sorry, the upload failed. Please try again.";
    }
  2. Retry logic

    function onUploadError( property, errors, multiple ) {
        data.retryCount++;
        if ( data.retryCount < 3 ) {
            // Trigger retry logic
        }
    }
  3. Analytics/logging

    function onUploadError( property, errors, multiple ) {
        getInstance( "AnalyticsService" )
            .trackEvent( "upload_failed", { property: property } );
    }
  4. Reset upload state

    function onUploadError( property, errors, multiple ) {
        data[ property ] = "";  // Clear the failed upload
        data.isUploading = false;
    }

Related Lifecycle Hooks

  • onUploadError() - Called when upload fails (this hook)
  • See the file upload documentation for complete upload lifecycle information

Notes

  • This hook is optional - if not defined, upload errors will be handled silently by the JavaScript error callback
  • The hook is called AFTER the upload:errored event is dispatched to the JavaScript layer
  • All three parameters are always provided, though errors may be null

@grantcopley grantcopley merged commit 339c68f into next Oct 10, 2025
2 checks passed
@grantcopley grantcopley deleted the copilot/fix-upload-errored-method branch October 10, 2025 15:32
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.

2 participants