patch 7.4.1857
Problem:    When a channel appends to a buffer that is 'nomodifiable' there is
            an error but appending is done anyway.
Solution:   Add the 'modifiable' option.  Refuse to write to a 'nomodifiable'
            when the value is 1.
diff --git a/src/channel.c b/src/channel.c
index 2cc46fe..973d234 100644
--- a/src/channel.c
+++ b/src/channel.c
@@ -1209,9 +1209,20 @@
 	}
 	if (buf != NULL)
 	{
-	    ch_logs(channel, "writing out to buffer '%s'",
+	    if (opt->jo_set & JO_OUT_MODIFIABLE)
+		channel->ch_part[PART_OUT].ch_nomodifiable =
+						!opt->jo_modifiable[PART_OUT];
+
+	    if (!buf->b_p_ma && !channel->ch_part[PART_OUT].ch_nomodifiable)
+	    {
+		EMSG(_(e_modifiable));
+	    }
+	    else
+	    {
+		ch_logs(channel, "writing out to buffer '%s'",
 						       (char *)buf->b_ffname);
-	    channel->ch_part[PART_OUT].ch_buffer = buf;
+		channel->ch_part[PART_OUT].ch_buffer = buf;
+	    }
 	}
     }
 
@@ -1236,9 +1247,19 @@
 	    buf = find_buffer(opt->jo_io_name[PART_ERR], TRUE);
 	if (buf != NULL)
 	{
-	    ch_logs(channel, "writing err to buffer '%s'",
+	    if (opt->jo_set & JO_ERR_MODIFIABLE)
+		channel->ch_part[PART_ERR].ch_nomodifiable =
+						!opt->jo_modifiable[PART_ERR];
+	    if (!buf->b_p_ma && !channel->ch_part[PART_ERR].ch_nomodifiable)
+	    {
+		EMSG(_(e_modifiable));
+	    }
+	    else
+	    {
+		ch_logs(channel, "writing err to buffer '%s'",
 						       (char *)buf->b_ffname);
-	    channel->ch_part[PART_ERR].ch_buffer = buf;
+		channel->ch_part[PART_ERR].ch_buffer = buf;
+	    }
 	}
     }
 
@@ -2107,11 +2128,23 @@
 }
 
     static void
-append_to_buffer(buf_T *buffer, char_u *msg, channel_T *channel)
+append_to_buffer(buf_T *buffer, char_u *msg, channel_T *channel, int part)
 {
     buf_T	*save_curbuf = curbuf;
     linenr_T    lnum = buffer->b_ml.ml_line_count;
     int		save_write_to = buffer->b_write_to_channel;
+    chanpart_T  *ch_part = &channel->ch_part[part];
+    int		save_p_ma = buffer->b_p_ma;
+
+    if (!buffer->b_p_ma && !ch_part->ch_nomodifiable)
+    {
+	if (!ch_part->ch_nomod_error)
+	{
+	    ch_error(channel, "Buffer is not modifiable, cannot append");
+	    ch_part->ch_nomod_error = TRUE;
+	}
+	return;
+    }
 
     /* If the buffer is also used as input insert above the last
      * line. Don't write these lines. */
@@ -2124,6 +2157,7 @@
     /* Append to the buffer */
     ch_logn(channel, "appending line %d to buffer", (int)lnum + 1);
 
+    buffer->b_p_ma = TRUE;
     curbuf = buffer;
     u_sync(TRUE);
     /* ignore undo failure, undo is not very useful here */
@@ -2132,6 +2166,10 @@
     ml_append(lnum, msg, 0, FALSE);
     appended_lines_mark(lnum, 1L);
     curbuf = save_curbuf;
+    if (ch_part->ch_nomodifiable)
+	buffer->b_p_ma = FALSE;
+    else
+	buffer->b_p_ma = save_p_ma;
 
     if (buffer->b_nwindows > 0)
     {
@@ -2359,7 +2397,7 @@
 		/* JSON or JS mode: re-encode the message. */
 		msg = json_encode(listtv, ch_mode);
 	    if (msg != NULL)
-		append_to_buffer(buffer, msg, channel);
+		append_to_buffer(buffer, msg, channel, part);
 	}
 
 	if (callback != NULL)
@@ -3915,6 +3953,16 @@
 		    return FAIL;
 		}
 	    }
+	    else if (STRCMP(hi->hi_key, "out_modifiable") == 0
+		    || STRCMP(hi->hi_key, "err_modifiable") == 0)
+	    {
+		part = part_from_char(*hi->hi_key);
+
+		if (!(supported & JO_OUT_IO))
+		    break;
+		opt->jo_set |= JO_OUT_MODIFIABLE << (part - PART_OUT);
+		opt->jo_modifiable[part] = get_tv_number(item);
+	    }
 	    else if (STRCMP(hi->hi_key, "in_top") == 0
 		    || STRCMP(hi->hi_key, "in_bot") == 0)
 	    {
diff --git a/src/structs.h b/src/structs.h
index 12a8a43..d5f8adc 100644
--- a/src/structs.h
+++ b/src/structs.h
@@ -1401,6 +1401,8 @@
     partial_T	*ch_partial;
 
     buf_T	*ch_buffer;	/* buffer to read from or write to */
+    int		ch_nomodifiable; /* TRUE when buffer can be 'nomodifiable' */
+    int		ch_nomod_error;	/* TRUE when e_modifiable was given */
     int		ch_buf_append;	/* write appended lines instead top-bot */
     linenr_T	ch_buf_top;	/* next line to send */
     linenr_T	ch_buf_bot;	/* last line to send */
@@ -1477,6 +1479,8 @@
 #define JO_IN_BUF	    0x4000000	/* "in_buf" (JO_OUT_BUF << 2) */
 #define JO_CHANNEL	    0x8000000	/* "channel" */
 #define JO_BLOCK_WRITE	    0x10000000	/* "block_write" */
+#define JO_OUT_MODIFIABLE   0x20000000	/* "out_modifiable" */
+#define JO_ERR_MODIFIABLE   0x40000000	/* "err_modifiable" (JO_OUT_ << 1) */
 #define JO_ALL		    0x7fffffff
 
 #define JO_MODE_ALL	(JO_MODE + JO_IN_MODE + JO_OUT_MODE + JO_ERR_MODE)
@@ -1500,6 +1504,7 @@
     char_u	jo_io_name_buf[4][NUMBUFLEN];
     char_u	*jo_io_name[4];	/* not allocated! */
     int		jo_io_buf[4];
+    int		jo_modifiable[4];
     channel_T	*jo_channel;
 
     linenr_T	jo_in_top;
diff --git a/src/testdir/test_channel.vim b/src/testdir/test_channel.vim
index 363b5cd..ed3fa6d 100644
--- a/src/testdir/test_channel.vim
+++ b/src/testdir/test_channel.vim
@@ -676,7 +676,7 @@
   endtry
 endfunc
 
-func Run_test_pipe_to_buffer(use_name)
+func Run_test_pipe_to_buffer(use_name, nomod)
   if !has('job')
     return
   endif
@@ -691,6 +691,9 @@
     quit
     let firstline = ''
   endif
+  if a:nomod
+    let options['out_modifiable'] = 0
+  endif
   let job = job_start(s:python . " test_channel_pipe.py", options)
   call assert_equal("run", job_status(job))
   try
@@ -705,6 +708,11 @@
       $del
     endif
     call assert_equal([firstline, 'line one', 'line two', 'this', 'AND this', 'Goodbye!'], getline(1, '$'))
+    if a:nomod
+      call assert_equal(0, &modifiable)
+    else
+      call assert_equal(1, &modifiable)
+    endif
     bwipe!
   finally
     call job_stop(job)
@@ -712,14 +720,18 @@
 endfunc
 
 func Test_pipe_to_buffer_name()
-  call Run_test_pipe_to_buffer(1)
+  call Run_test_pipe_to_buffer(1, 0)
 endfunc
 
 func Test_pipe_to_buffer_nr()
-  call Run_test_pipe_to_buffer(0)
+  call Run_test_pipe_to_buffer(0, 0)
 endfunc
 
-func Run_test_pipe_err_to_buffer(use_name)
+func Test_pipe_to_buffer_name_nomod()
+  call Run_test_pipe_to_buffer(1, 1)
+endfunc
+
+func Run_test_pipe_err_to_buffer(use_name, nomod)
   if !has('job')
     return
   endif
@@ -734,6 +746,9 @@
     quit
     let firstline = ''
   endif
+  if a:nomod
+    let options['err_modifiable'] = 0
+  endif
   let job = job_start(s:python . " test_channel_pipe.py", options)
   call assert_equal("run", job_status(job))
   try
@@ -745,6 +760,11 @@
     sp pipe-err
     call s:waitFor('line("$") >= 5')
     call assert_equal([firstline, 'line one', 'line two', 'this', 'AND this'], getline(1, '$'))
+    if a:nomod
+      call assert_equal(0, &modifiable)
+    else
+      call assert_equal(1, &modifiable)
+    endif
     bwipe!
   finally
     call job_stop(job)
@@ -752,11 +772,15 @@
 endfunc
 
 func Test_pipe_err_to_buffer_name()
-  call Run_test_pipe_err_to_buffer(1)
+  call Run_test_pipe_err_to_buffer(1, 0)
 endfunc
   
 func Test_pipe_err_to_buffer_nr()
-  call Run_test_pipe_err_to_buffer(0)
+  call Run_test_pipe_err_to_buffer(0, 0)
+endfunc
+  
+func Test_pipe_err_to_buffer_name_nomod()
+  call Run_test_pipe_err_to_buffer(1, 1)
 endfunc
   
 func Test_pipe_both_to_buffer()
diff --git a/src/version.c b/src/version.c
index e47ab53..c3afbad 100644
--- a/src/version.c
+++ b/src/version.c
@@ -754,6 +754,8 @@
 static int included_patches[] =
 {   /* Add new patch number below this line */
 /**/
+    1857,
+/**/
     1856,
 /**/
     1855,