diff --git a/go/builder.go b/go/builder.go
index c7aa264c7c3188e3a9140644e7eae506554166ea..7533dddf2c65ba29d85d6e67a8eb531f4e28c14c 100644
--- a/go/builder.go
+++ b/go/builder.go
@@ -8,11 +8,12 @@ package flatbuffers
 type Builder struct {
 	Bytes []byte
 
-	minalign  int
-	vtable    []UOffsetT
-	objectEnd UOffsetT
-	vtables   []UOffsetT
-	head      UOffsetT
+	minalign     int
+	vtable       []UOffsetT
+	objectEnd    UOffsetT
+	insideObject bool
+	vtables      []UOffsetT
+	head         UOffsetT
 }
 
 // NewBuilder initializes a Builder of size `initial_size`.
@@ -53,6 +54,8 @@ func (b *Builder) Reset() {
 // StartObject initializes bookkeeping for writing a new object.
 func (b *Builder) StartObject(numfields int) {
 	b.notNested()
+	b.insideObject = true
+
 	// use 32-bit offsets so that arithmetic doesn't overflow.
 	if cap(b.vtable) < numfields || b.vtable == nil {
 		b.vtable = make([]UOffsetT, numfields)
@@ -170,10 +173,12 @@ func (b *Builder) WriteVtable() (n UOffsetT) {
 
 // EndObject writes data necessary to finish object construction.
 func (b *Builder) EndObject() UOffsetT {
-	if b.vtable == nil {
+	if !b.insideObject {
 		panic("not in object")
 	}
-	return b.WriteVtable()
+	n := b.WriteVtable()
+	b.insideObject = false
+	return n
 }
 
 // Doubles the size of the byteslice, and copies the old data towards the
@@ -281,6 +286,8 @@ func (b *Builder) EndVector(vectorNumElems int) UOffsetT {
 
 // CreateString writes a null-terminated string as a vector.
 func (b *Builder) CreateString(s string) UOffsetT {
+	b.notNested()
+
 	b.Prep(int(SizeUOffsetT), (len(s)+1)*SizeByte)
 	b.PlaceByte(0)
 
@@ -294,6 +301,8 @@ func (b *Builder) CreateString(s string) UOffsetT {
 
 // CreateByteString writes a byte slice as a string (null-terminated).
 func (b *Builder) CreateByteString(s []byte) UOffsetT {
+	b.notNested()
+
 	b.Prep(int(SizeUOffsetT), (len(s)+1)*SizeByte)
 	b.PlaceByte(0)
 
@@ -320,7 +329,7 @@ func (b *Builder) CreateByteVector(v []byte) UOffsetT {
 func (b *Builder) notNested() {
 	// Check that no other objects are being built while making this
 	// object. If not, panic:
-	if len(b.vtable) > 0 {
+	if b.insideObject {
 		panic("non-inline data write inside of object")
 	}
 }
diff --git a/tests/go_test.go b/tests/go_test.go
index 070045a1d1b2caddb03ca98ec670141f59332976..18a6b8e2e93baae8b9eb7a2202163c10f89743c5 100644
--- a/tests/go_test.go
+++ b/tests/go_test.go
@@ -68,6 +68,13 @@ func TestAll(t *testing.T) {
 	// expected bytes (does not use any schema):
 	CheckByteLayout(t.Fatalf)
 
+	// Verify that panics are raised during exceptional conditions:
+	CheckNotInObjectError(t.Fatalf)
+	CheckObjectIsNestedError(t.Fatalf)
+	CheckStringIsNestedError(t.Fatalf)
+	CheckByteStringIsNestedError(t.Fatalf)
+	CheckStructIsNotInlineError(t.Fatalf)
+
 	// Verify that using the generated Go code builds a buffer without
 	// returning errors:
 	generated, off := CheckGeneratedBuild(t.Fatalf)
@@ -540,7 +547,7 @@ func CheckByteLayout(fail func(string, ...interface{})) {
 	// We use escape codes here so that editors without unicode support
 	// aren't bothered:
 	uni_str := "\u65e5\u672c\u8a9e"
-	b.CreateString(uni_str)  
+	b.CreateString(uni_str)
 	check([]byte{9, 0, 0, 0, 230, 151, 165, 230, 156, 172, 232, 170, 158, 0, //  null-terminated, 2-byte pad
 		0, 0})
 
@@ -1096,6 +1103,76 @@ func CheckVtableDeduplication(fail func(string, ...interface{})) {
 	testTable(table2, 0, 77, 88, 99)
 }
 
+// CheckNotInObjectError verifies that `EndObject` fails if not inside an
+// object.
+func CheckNotInObjectError(fail func(string, ...interface{})) {
+	b := flatbuffers.NewBuilder(0)
+
+	defer func() {
+		r := recover()
+		if r == nil {
+			fail("expected panic in CheckNotInObjectError")
+		}
+	}()
+	b.EndObject()
+}
+
+// CheckObjectIsNestedError verifies that an object can not be created inside
+// another object.
+func CheckObjectIsNestedError(fail func(string, ...interface{})) {
+	b := flatbuffers.NewBuilder(0)
+	b.StartObject(0)
+	defer func() {
+		r := recover()
+		if r == nil {
+			fail("expected panic in CheckObjectIsNestedError")
+		}
+	}()
+	b.StartObject(0)
+}
+
+// CheckStringIsNestedError verifies that a string can not be created inside
+// another object.
+func CheckStringIsNestedError(fail func(string, ...interface{})) {
+	b := flatbuffers.NewBuilder(0)
+	b.StartObject(0)
+	defer func() {
+		r := recover()
+		if r == nil {
+			fail("expected panic in CheckStringIsNestedError")
+		}
+	}()
+	b.CreateString("foo")
+}
+
+// CheckByteStringIsNestedError verifies that a bytestring can not be created
+// inside another object.
+func CheckByteStringIsNestedError(fail func(string, ...interface{})) {
+	b := flatbuffers.NewBuilder(0)
+	b.StartObject(0)
+	defer func() {
+		r := recover()
+		if r == nil {
+			fail("expected panic in CheckByteStringIsNestedError")
+		}
+	}()
+	b.CreateByteString([]byte("foo"))
+}
+
+// CheckStructIsNotInlineError verifies that writing a struct in a location
+// away from where it is used will cause a panic.
+func CheckStructIsNotInlineError(fail func(string, ...interface{})) {
+	b := flatbuffers.NewBuilder(0)
+	b.StartObject(0)
+	defer func() {
+		r := recover()
+		if r == nil {
+			fail("expected panic in CheckStructIsNotInlineError")
+		}
+	}()
+	b.PrependStructSlot(0, 1, 0)
+}
+
 // CheckDocExample checks that the code given in FlatBuffers documentation
 // is syntactically correct.
 func CheckDocExample(buf []byte, off flatbuffers.UOffsetT, fail func(string, ...interface{})) {