diff --git a/node-api/src/main/kotlin/net/corda/nodeapi/internal/serialization/amqp/SerializationHelper.kt b/node-api/src/main/kotlin/net/corda/nodeapi/internal/serialization/amqp/SerializationHelper.kt
index 8b677630d2..57903f546e 100644
--- a/node-api/src/main/kotlin/net/corda/nodeapi/internal/serialization/amqp/SerializationHelper.kt
+++ b/node-api/src/main/kotlin/net/corda/nodeapi/internal/serialization/amqp/SerializationHelper.kt
@@ -1,9 +1,9 @@
 package net.corda.nodeapi.internal.serialization.amqp
 
-import net.corda.core.serialization.ClassWhitelist
-import net.corda.core.serialization.CordaSerializable
 import com.google.common.primitives.Primitives
 import com.google.common.reflect.TypeToken
+import net.corda.core.serialization.ClassWhitelist
+import net.corda.core.serialization.CordaSerializable
 import net.corda.core.serialization.SerializationContext
 import org.apache.qpid.proton.codec.Data
 import java.beans.IndexedPropertyDescriptor
@@ -81,10 +81,17 @@ private fun <T : Any> propertiesForSerializationFromConstructor(kotlinConstructo
     val rc: MutableList<PropertySerializer> = ArrayList(kotlinConstructor.parameters.size)
     for (param in kotlinConstructor.parameters) {
         val name = param.name ?: throw NotSerializableException("Constructor parameter of $clazz has no name.")
+
         val matchingProperty = properties[name] ?:
-                throw NotSerializableException("No property matching constructor parameter named '$name' of '$clazz'. " +
-                        "If using Java, check that you have the -parameters option specified in the Java compiler. " +
-                        "Alternately, provide a proxy serializer (SerializationCustomSerializer) if recompiling isn't an option")
+                try {
+                    clazz.getDeclaredField(param.name)
+                    throw NotSerializableException("Property '$name' or it's getter is non public, this renders class '$clazz' unserializable")
+                } catch (e: NoSuchFieldException) {
+                    throw NotSerializableException("No property matching constructor parameter named '$name' of '$clazz'. " +
+                            "If using Java, check that you have the -parameters option specified in the Java compiler. " +
+                            "Alternately, provide a proxy serializer (SerializationCustomSerializer) if recompiling isn't an option")
+                }
+
         // Check that the method has a getter in java.
         val getter = matchingProperty.readMethod ?: throw NotSerializableException("Property has no getter method for $name of $clazz. " +
                 "If using Java and the parameter name looks anonymous, check that you have the -parameters option specified in the Java compiler." +
diff --git a/node-api/src/test/java/net/corda/nodeapi/internal/serialization/amqp/ErrorMessageTests.java b/node-api/src/test/java/net/corda/nodeapi/internal/serialization/amqp/ErrorMessageTests.java
new file mode 100644
index 0000000000..2df95a808d
--- /dev/null
+++ b/node-api/src/test/java/net/corda/nodeapi/internal/serialization/amqp/ErrorMessageTests.java
@@ -0,0 +1,40 @@
+package net.corda.nodeapi.internal.serialization.amqp;
+
+import net.corda.nodeapi.internal.serialization.AllWhitelist;
+import org.assertj.core.api.Assertions;
+import org.junit.Test;
+
+import java.io.NotSerializableException;
+
+public class ErrorMessageTests {
+    private String errMsg(String property, String testname) {
+        return "Property '"
+                + property
+                + "' or it's getter is non public, this renders class 'class "
+                + testname
+                + "$C' unserializable -> class "
+                + testname
+                + "$C";
+    }
+
+    static class C {
+        public Integer a;
+
+        public C(Integer a) {
+            this.a = a;
+        }
+
+        private Integer getA() { return this.a; }
+    }
+
+    @Test
+    public void testJavaConstructorAnnotations() {
+        SerializerFactory factory1 = new SerializerFactory(AllWhitelist.INSTANCE, ClassLoader.getSystemClassLoader());
+        SerializationOutput ser = new SerializationOutput(factory1);
+
+        Assertions.assertThatThrownBy(() -> ser.serialize(new C(1)))
+                .isInstanceOf(NotSerializableException.class)
+                .hasMessage(errMsg("a", getClass().getName()));
+    }
+
+}
diff --git a/node-api/src/test/kotlin/net/corda/nodeapi/internal/serialization/amqp/ErrorMessagesTests.kt b/node-api/src/test/kotlin/net/corda/nodeapi/internal/serialization/amqp/ErrorMessagesTests.kt
new file mode 100644
index 0000000000..775e5c3405
--- /dev/null
+++ b/node-api/src/test/kotlin/net/corda/nodeapi/internal/serialization/amqp/ErrorMessagesTests.kt
@@ -0,0 +1,69 @@
+package net.corda.nodeapi.internal.serialization.amqp
+
+import org.assertj.core.api.Assertions
+import org.junit.Test
+import java.io.NotSerializableException
+
+class ErrorMessagesTests {
+    companion object {
+        val VERBOSE get() = false
+    }
+
+    private fun errMsg(property:String, testname: String) =
+            "Property '$property' or it's getter is non public, this renders class 'class $testname\$C' unserializable -> class $testname\$C"
+
+    @Test
+    fun privateProperty() {
+        data class C(private val a: Int)
+
+        val sf = testDefaultFactory()
+
+        val testname = "${javaClass.name}\$${testName()}"
+
+        Assertions.assertThatThrownBy {
+            TestSerializationOutput(VERBOSE, sf).serialize(C(1))
+        }.isInstanceOf(NotSerializableException::class.java).hasMessage(errMsg("a", testname))
+    }
+
+    @Test
+    fun privateProperty2() {
+        data class C(val a: Int, private val b: Int)
+
+        val sf = testDefaultFactory()
+
+        val testname = "${javaClass.name}\$${testName()}"
+
+        Assertions.assertThatThrownBy {
+            TestSerializationOutput(VERBOSE, sf).serialize(C(1, 2))
+        }.isInstanceOf(NotSerializableException::class.java).hasMessage(errMsg("b", testname))
+    }
+
+    @Test
+    fun privateProperty3() {
+        // despite b being private, the getter we've added is public and thus allows for the serialisation
+        // of the object
+        data class C(val a: Int, private val b: Int) {
+            public fun getB() = b
+        }
+
+        val sf = testDefaultFactory()
+
+        val testname = "${javaClass.name}\$${testName()}"
+
+        val bytes = TestSerializationOutput(VERBOSE, sf).serialize(C(1, 2))
+        val c = DeserializationInput(sf).deserialize(bytes)
+    }
+
+    @Test
+    fun protectedProperty() {
+        data class C(protected val a: Int)
+
+        val sf = testDefaultFactory()
+
+        val testname = "${javaClass.name}\$${testName()}"
+
+        Assertions.assertThatThrownBy {
+            TestSerializationOutput(VERBOSE, sf).serialize(C(1))
+        }.isInstanceOf(NotSerializableException::class.java).hasMessage(errMsg("a", testname))
+    }
+}
\ No newline at end of file