I have a very simple page:

<!-- vf page -->
<apex:page standardController="Challenge__c" extensions="upsertChallengeResponse" sidebar="false" tabstyle="ChallengesVF__tab"  standardStylesheets="true" showHeader="true">
        <!-- Latest compiled and minified CSS -->
        <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css" integrity="sha384-1q8mTJOASx8j1Au+a5WDVnPi2lkFfwwEAa8hDDdjZlpLegxhjVME1fgjWPGmkzs7" crossorigin="anonymous"/>

        <!-- Optional theme -->
        <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap-theme.min.css" integrity="sha384-fLW2N01lMqjakBkx3l/M9EahuwpSfeNvV63J5ezn3uZzapT0u7EYsXMjQV+0En5r" crossorigin="anonymous"/>

        <!-- jQuery library -->
        <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.2/jquery.min.js"></script>

        <!-- Latest compiled and minified JavaScript -->
        <script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/js/bootstrap.min.js" integrity="sha384-0mSbJDEHialfmuBBQP6A4Qrprq5OVfW37PRR3j5ELqxss1yVqOtnepnHVP9aJ7xS" crossorigin="anonymous"></script>
            .mypage {
            font-family: "ProximaNovaSoft-Regular", Calibri;
            font-size: 110%;
            padding-top: 12px;
            padding-bottom: 12px;
            padding-left: 12px;
            .mypage h2 {
            margin-left: 15px;
            font-weight: bold;
            font-size: 24px;
            .mypage ul {
            list-style-type: none;
            padding: 0;
            .mypage li {
            margin: 3px;
            .btn-bt {
            display: inline-block !important;
            padding: .375rem 1rem !important;
            font-size: 2rem !important;
            font-weight: 400 !important;
            line-height: 1.5 !important;
            text-align: center !important;
            white-space: nowrap !important;
            vertical-align: middle !important;
            cursor: pointer !important;
            -webkit-user-select: none !important;
            -moz-user-select: none !important;
            -ms-user-select: none !important;
            user-select: none !important;
            border: 1px solid transparent !important;
            border-radius: .25rem !important;
            margin: 0px !important;
            color: #fff !important;
            background: #fca61e !important;
            background-color: #fca61e !important;
            border-color: #fca61e !important;
            .btn-bt.btn-walmart-primary {
            color: #fff !important;
            background: #fca61e !important;
            background-color: #fca61e !important;
            border-color: #fca61e !important;
            div.jumbotron {
            color: #286090;
            div.jumbotron p{
            color: #fca61e;
            <div class="container">
                <div class="jumbotron">
                        <apex:outputField value="{!chal.name}"/>
                    <p>Challenge Response</p>
                <div class="container theme-showcase" role="main">
                    <div class="form-group">
                        <apex:form >
                            <apex:inputTextarea styleClass="form-control" style="height: 200px;" value="{!challengeAccepted.Response__c}"/>

                            <apex:inputfile value="{!myfile.body}" filename="{!myfile.Name}" styleClass="file-chooser" />

                            <apex:actionFunction name="callSaveDocAndFields" action="{!SaveDocAndFields}" />
                            <button type="submit" class="btn-bt btn-walmart-primary step-btn next" onClick="callSaveDocAndFields();"> Submit </button>

                            <apex:commandButton value="Submit" action="{!SaveDocAndFields}" styleClass="btn-bt btn-walmart-primary step-btn next" />

and a very simple controller

// controller: (upsertChallengeResponse.cls)
public class upsertChallengeResponse{
    public String currentRecordId {get;set;}
    public String parameterValue {get;set;}
    public Challenge__c chal{get;set;}
    public Challenge_Accepted__c challengeAccepted { get; set; }

    public Attachment myFile { get; set; }

    public Pagereference saveDocAndFields()
        insert challengeAccepted;

        myfile.parentId = challengeAccepted.Id;
        insert myfile;
        myfile = null;

        return null;

    public upsertChallengeResponse(ApexPages.StandardController controller) {
        currentRecordId  = ApexPages.CurrentPage().getparameters().get('id');
        chal = [SELECT Id, Name, Due_Date__c, Award_Due_Date__c, Challenge_Detail__c, Type_of_deliverable__c, Number_of_Winners_Possible__c, Reward__c 
                  FROM Challenge__c 
                 WHERE Id =: currentRecordId];
        parameterValue = ApexPages.CurrentPage().getparameters().get('nameParam');

        challengeAccepted = new Challenge_Accepted__c();
        challengeAccepted.Challenge__c = currentRecordId;

        myFile = new Attachment();


Current status:

  • When I attach a file and save it using the COMMAND BUTTON, there is no problem: the record is being created, and the file is getting successfully attached to the created record.
  • No viewstate errors


Why am I hitting a viewstate error when I use the BUTTON TAG + ACTION FUNCTION combo, instead of the COMMAND BUTTON?

  • whenever you use inputFile, the associated body setter had better be transient when doing an ajax refresh (action method returning null).
    – cropredy
    Commented May 13, 2016 at 5:19

1 Answer 1


@cropredy gave you the solution, but not the explanation behind it. I think that's an important part of answering your question. Your issue is occurring for several reasons, one of which is related to the behavior of a CommandButton with a Standard Controller.

By definition, a CommandButton:

executes an action defined by a controller, and then either refreshes the current page, or navigates to a different page based on the PageReference variable that is returned by the action.

So, even though your method doesn't return a PageReference, using a CommandButton to call the method, forces a page refresh because the redirect property hasn't been set to either true or false. This clears the view state and either reloads the record or leaves the page ready for a new one to be called into context so the controller can do a get on it.

This is because of the 2nd reason for the behavior you're seeing: Visualforce Order of Execution. Now when you use a regular Button with the ActionFunction, the PostBack Request Example on Examples of Visualforce Page Execution Order (last part of 3rd example near the bottom of page) comes into play.

In that situation as with yours, the view state is not cleared when the page is refreshed. Instead, it has to maintain the view state which includes all the memory required to hold the attachment body submitted via your form. Had you used the transient keyword on those variables, the controller wouldn't have been required to maintain the state of their values after the action method submitted your form to insert the record with the attachment.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .