Retrofit. java.net.ProtocolException: expected * bytes but received *

Viewed 7576

I'm trying to do a Multipart POST request through Retrofit2, where I upload to the API a custom file.

It randomly fails with this Exception:

W/System.err: java.net.ProtocolException: expected 154 bytes but received 634

Does anyone could put some light on it?

This is my code in the interface:

@Multipart
@POST("recordings/{id}/{rec_id}/")
Call<ResponseBody> uploadRecording(@Path("id") String id, @Path("rec_id") String rec_id, @Part MultipartBody.Part bleFile);

In the constructor:

public ApiConnectionManager(Context con){
    Gson gson = new GsonBuilder()
            .setDateFormat("yyyy-MM-dd'T'HH:mm:ssZ")
            .create();

    OkHttpClient.Builder client = new OkHttpClient.Builder();
    HttpLoggingInterceptor loggingInterceptor = new HttpLoggingInterceptor();
    loggingInterceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
    client.addInterceptor(loggingInterceptor);

    Retrofit retrofit = new Retrofit.Builder()
            .baseUrl(con.getResources().getString(R.string.api_url)) // API url is hidden
            .addConverterFactory(GsonConverterFactory.create(gson))
            .client(client.build())
            .build();

    this.companyAPI = retrofit.create(CompanyAPI.class);
}

and in the upload method:

private void uploadFile(String id, final File bleFile) {
    MediaType MEDIA_TYPE = MediaType.parse("multipart/mixed");
    RequestBody requestBody = RequestBody.create(MEDIA_TYPE,bleFile);
    MultipartBody.Part partFile = MultipartBody.Part.createFormData("file", bleFile.getName(), requestBody);
    String recordingId = bleFile.getName().replace(".BLE","");
    Call<ResponseBody> call = companyAPI.uploadRecording(id, recordingId, partFile);
    call.enqueue(new Callback<ResponseBody>() {
        @Override
        public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) {
            Log.d(TAG+"-Upload "+bleFile.getName(),response.message());
        }

        @Override
        public void onFailure(Call<ResponseBody> call, Throwable t) {
            Log.d(TAG,"FAILED");
            t.printStackTrace();
        }
    });
}
6 Answers

I have encountered the same issue and solved by creating a temporary file before upload it.

In Kotlin.

fun createTemoraryFile(context: Context, uri: Uri): File {
    val inputStream = context.contentResolver.openInputStream(uri)
    val f = createTempFile(
        directory = context.cacheDir
        )
    inputStream.copyTo(f.outputStream())
    return f
}

And after upload finished, I deleted the temporary file.

It means that file what you're trying to send is still creating and it's size changing. You should finalize your file first and then send.

In my case, I used HttpUrlConnection for Uploading File/Bitmap/Buffer as Multi-Part protocol uploading...

short Answer :

I removed following line in my code and every things worked fine :

// remove this line 
connection.setFixedLengthStreamingMode(dataToUpload.length);

long Answer :

for multi-part upload we must write some extra data such as boundary, twoHyphens (--) , newLine (\r\n)... Therefore, the length of the data will be longer than the length of the data(file/bitmap/buffered).

By deleting the setFixedLengthStreamingMode in connection request, We can solves this problem.

But, If it is necessary to send this file or data length, we must calculate the total length.

Related