diff --git a/ee/app/assets/javascripts/analytics/cycle_analytics/store/actions/value_streams.js b/ee/app/assets/javascripts/analytics/cycle_analytics/store/actions/value_streams.js
index 92d58e449f564d0a6a8411013c01a37edfee9f75..34538026f62c8b10be19573594f7d1daa3ea046d 100644
--- a/ee/app/assets/javascripts/analytics/cycle_analytics/store/actions/value_streams.js
+++ b/ee/app/assets/javascripts/analytics/cycle_analytics/store/actions/value_streams.js
@@ -1,31 +1,6 @@
-import {
-  createValueStream as apiCreateValueStream,
-  updateValueStream as apiUpdateValueStream,
-  deleteValueStream as apiDeleteValueStream,
-  getValueStreams,
-} from 'ee/api/analytics_api';
+import { deleteValueStream as apiDeleteValueStream, getValueStreams } from 'ee/api/analytics_api';
 import * as types from '../mutation_types';
 
-export const createValueStream = ({ commit, getters }, data) => {
-  const { namespaceRestApiRequestPath } = getters;
-  commit(types.REQUEST_CREATE_VALUE_STREAM);
-
-  return apiCreateValueStream(namespaceRestApiRequestPath, data).catch(({ response } = {}) => {
-    const { data: { message, payload: { errors } } = null } = response;
-    commit(types.RECEIVE_CREATE_VALUE_STREAM_ERROR, { message, errors, data });
-  });
-};
-
-export const updateValueStream = ({ commit, getters }, { id: valueStreamId, ...data }) => {
-  const { namespaceRestApiRequestPath: namespacePath } = getters;
-  commit(types.REQUEST_UPDATE_VALUE_STREAM);
-
-  return apiUpdateValueStream({ namespacePath, valueStreamId, data }).catch(({ response } = {}) => {
-    const { data: { message, payload: { errors } } = null } = response;
-    commit(types.RECEIVE_UPDATE_VALUE_STREAM_ERROR, { message, errors, data });
-  });
-};
-
 export const deleteValueStream = ({ commit, dispatch, getters }, valueStreamId) => {
   const { namespaceRestApiRequestPath } = getters;
   commit(types.REQUEST_DELETE_VALUE_STREAM);
diff --git a/ee/app/assets/javascripts/analytics/cycle_analytics/store/mutation_types.js b/ee/app/assets/javascripts/analytics/cycle_analytics/store/mutation_types.js
index 502ff65c703ce302095fcccf218c3a6da6a27b13..52e6a63166c99175631263901efe3e7f8e676eaf 100644
--- a/ee/app/assets/javascripts/analytics/cycle_analytics/store/mutation_types.js
+++ b/ee/app/assets/javascripts/analytics/cycle_analytics/store/mutation_types.js
@@ -35,12 +35,6 @@ export const RECEIVE_GROUP_LABELS_ERROR = 'RECEIVE_GROUP_LABELS_ERROR';
 export const INITIALIZE_VSA = 'INITIALIZE_VSA';
 export const INITIALIZE_VALUE_STREAM_SUCCESS = 'INITIALIZE_VALUE_STREAM_SUCCESS';
 
-export const REQUEST_CREATE_VALUE_STREAM = 'REQUEST_CREATE_VALUE_STREAM';
-export const RECEIVE_CREATE_VALUE_STREAM_ERROR = 'RECEIVE_CREATE_VALUE_STREAM_ERROR';
-
-export const REQUEST_UPDATE_VALUE_STREAM = 'REQUEST_UPDATE_VALUE_STREAM';
-export const RECEIVE_UPDATE_VALUE_STREAM_ERROR = 'RECEIVE_UPDATE_VALUE_STREAM_ERROR';
-
 export const REQUEST_DELETE_VALUE_STREAM = 'REQUEST_DELETE_VALUE_STREAM';
 export const RECEIVE_DELETE_VALUE_STREAM_SUCCESS = 'RECEIVE_DELETE_VALUE_STREAM_SUCCESS';
 export const RECEIVE_DELETE_VALUE_STREAM_ERROR = 'RECEIVE_DELETE_VALUE_STREAM_ERROR';
diff --git a/ee/app/assets/javascripts/analytics/cycle_analytics/store/mutations.js b/ee/app/assets/javascripts/analytics/cycle_analytics/store/mutations.js
index e3e57e1b55b335629394b1bf1a269fc352dd317d..eeec6e52f517b5ebe5a885e89304ccc8ac88afe2 100644
--- a/ee/app/assets/javascripts/analytics/cycle_analytics/store/mutations.js
+++ b/ee/app/assets/javascripts/analytics/cycle_analytics/store/mutations.js
@@ -3,7 +3,7 @@ import {
   PAGINATION_SORT_DIRECTION_DESC,
 } from '~/analytics/cycle_analytics/constants';
 import { convertObjectPropsToCamelCase } from '~/lib/utils/common_utils';
-import { transformRawStages, prepareStageErrors, formatMedianValues } from '../utils';
+import { transformRawStages, formatMedianValues } from '../utils';
 import * as types from './mutation_types';
 
 export default {
@@ -149,20 +149,6 @@ export default {
   [types.INITIALIZE_VALUE_STREAM_SUCCESS](state) {
     state.isLoading = false;
   },
-  [types.REQUEST_CREATE_VALUE_STREAM](state) {
-    state.createValueStreamErrors = {};
-  },
-  [types.RECEIVE_CREATE_VALUE_STREAM_ERROR](state, { data: { stages = [] }, errors = {} }) {
-    const { stages: stageErrors = {}, ...rest } = errors;
-    state.createValueStreamErrors = { ...rest, stages: prepareStageErrors(stages, stageErrors) };
-  },
-  [types.REQUEST_UPDATE_VALUE_STREAM](state) {
-    state.createValueStreamErrors = {};
-  },
-  [types.RECEIVE_UPDATE_VALUE_STREAM_ERROR](state, { data: { stages = [] }, errors = {} }) {
-    const { stages: stageErrors = {}, ...rest } = errors;
-    state.createValueStreamErrors = { ...rest, stages: prepareStageErrors(stages, stageErrors) };
-  },
   [types.REQUEST_DELETE_VALUE_STREAM](state) {
     state.isDeletingValueStream = true;
     state.deleteValueStreamError = null;
diff --git a/ee/app/assets/javascripts/analytics/cycle_analytics/store/state.js b/ee/app/assets/javascripts/analytics/cycle_analytics/store/state.js
index 98fe4c59f0d05a0e864e30fba5e33483a3e62110..fda1284b850884360ec1e0f5277fb65257b36e08 100644
--- a/ee/app/assets/javascripts/analytics/cycle_analytics/store/state.js
+++ b/ee/app/assets/javascripts/analytics/cycle_analytics/store/state.js
@@ -30,7 +30,6 @@ export default () => ({
   isFetchingGroupLabels: false,
   isFetchingGroupStagesAndEvents: false,
 
-  createValueStreamErrors: {},
   deleteValueStreamError: null,
 
   stages: [],
diff --git a/ee/app/assets/javascripts/analytics/cycle_analytics/utils.js b/ee/app/assets/javascripts/analytics/cycle_analytics/utils.js
index a331824be3e6a1ae1397eddf0e91ff126287bac9..2309b5ee7fa6f5e468ae6885dc07701df4e4b11a 100644
--- a/ee/app/assets/javascripts/analytics/cycle_analytics/utils.js
+++ b/ee/app/assets/javascripts/analytics/cycle_analytics/utils.js
@@ -63,19 +63,6 @@ export const transformRawTasksByTypeData = (data = []) => {
   return data.map((d) => convertObjectPropsToCamelCase(d, { deep: true }));
 };
 
-/**
- * Prepares the stage errors for use in the create value stream form
- *
- * The JSON error response returns a key value pair, the key corresponds to the
- * index of the stage with errors and the value is the returned error(s)
- *
- * @param {Array} stages - Array of value stream stages
- * @param {Object} errors - Key value pair of stage errors
- * @returns {Array} Returns and array of stage error objects
- */
-export const prepareStageErrors = (stages, errors) =>
-  stages.length ? stages.map((_, index) => convertObjectPropsToCamelCase(errors[index]) || {}) : [];
-
 /**
  * Takes the duration data for selected stages, transforms the date values and returns
  * the data in a flattened array
diff --git a/ee/app/assets/javascripts/analytics/cycle_analytics/vsa_settings/components/stories_constants.js b/ee/app/assets/javascripts/analytics/cycle_analytics/vsa_settings/components/stories_constants.js
index 9a1273bc43bcc187fff376d52664cb66fac0613d..af51569399e3330c882c3175f0cf9ec752076dfc 100644
--- a/ee/app/assets/javascripts/analytics/cycle_analytics/vsa_settings/components/stories_constants.js
+++ b/ee/app/assets/javascripts/analytics/cycle_analytics/vsa_settings/components/stories_constants.js
@@ -169,12 +169,3 @@ export const selectedValueStreamStages = ({ hideStages = false, addCustomStage =
   ...(addCustomStage ? [customStage] : []),
   ...defaultStageConfig.map(({ custom, name }) => ({ custom, name, hidden: hideStages })),
 ];
-
-export const formSubmissionErrors = {
-  name: ['has already been taken'],
-  stages: [
-    {
-      name: ['has already been taken'],
-    },
-  ],
-};
diff --git a/ee/app/assets/javascripts/analytics/cycle_analytics/vsa_settings/components/value_stream_form.stories.js b/ee/app/assets/javascripts/analytics/cycle_analytics/vsa_settings/components/value_stream_form.stories.js
index b5248877a560bc9eceba7f08eb5e136a678b201f..d6a30ba0f2edc4d2524bda34941eb2ba1b15c8c2 100644
--- a/ee/app/assets/javascripts/analytics/cycle_analytics/vsa_settings/components/value_stream_form.stories.js
+++ b/ee/app/assets/javascripts/analytics/cycle_analytics/vsa_settings/components/value_stream_form.stories.js
@@ -5,7 +5,6 @@ import {
   formEvents,
   selectedValueStream,
   selectedValueStreamStages,
-  formSubmissionErrors as createValueStreamErrors,
 } from './stories_constants';
 import ValueStreamForm from './value_stream_form.vue';
 
@@ -78,19 +77,6 @@ export const EditValueStreamWithHiddenStages = {
   },
 };
 
-export const WithFormSubmissionErrors = {
-  render: createStoryWithState({
-    state: {
-      selectedValueStream,
-      stages: selectedValueStreamStages({ addCustomStage: true }),
-      createValueStreamErrors,
-    },
-  }),
-  args: {
-    isEditing: true,
-  },
-};
-
 export const Loading = {
   render: createStoryWithState({
     state: {
diff --git a/ee/app/assets/javascripts/analytics/cycle_analytics/vsa_settings/components/value_stream_form_content.vue b/ee/app/assets/javascripts/analytics/cycle_analytics/vsa_settings/components/value_stream_form_content.vue
index 900ac0ceeda999dc274b892a655a8fe0051847f2..0a59b123aef0ade86933d3a4ea243e44936af96d 100644
--- a/ee/app/assets/javascripts/analytics/cycle_analytics/vsa_settings/components/value_stream_form_content.vue
+++ b/ee/app/assets/javascripts/analytics/cycle_analytics/vsa_settings/components/value_stream_form_content.vue
@@ -2,7 +2,7 @@
 import { GlAlert, GlButton, GlForm, GlFormInput, GlFormGroup, GlFormRadioGroup } from '@gitlab/ui';
 import { cloneDeep, uniqueId } from 'lodash';
 // eslint-disable-next-line no-restricted-imports
-import { mapState, mapActions } from 'vuex';
+import { mapState, mapGetters } from 'vuex';
 import { filterStagesByHiddenStatus } from '~/analytics/cycle_analytics/utils';
 import { swapArrayItems } from '~/lib/utils/array_utility';
 import { sprintf } from '~/locale';
@@ -10,12 +10,14 @@ import Tracking from '~/tracking';
 import CrudComponent from '~/vue_shared/components/crud_component.vue';
 import { visitUrlWithAlerts, mergeUrlParams } from '~/lib/utils/url_utility';
 import { getLabelEventsIdentifiers } from 'ee/analytics/cycle_analytics/utils';
+import { createValueStream, updateValueStream } from 'ee/api/analytics_api';
 import {
   validateValueStreamName,
   cleanStageName,
   validateStage,
   formatStageDataForSubmission,
   hasDirtyStage,
+  prepareStageErrors,
 } from '../utils';
 import {
   STAGE_SORT_DIRECTION,
@@ -99,13 +101,8 @@ export default {
     };
   },
   computed: {
-    ...mapState([
-      'isFetchingGroupLabels',
-      'formEvents',
-      'defaultGroupLabels',
-      'createValueStreamErrors',
-      'selectedValueStream',
-    ]),
+    ...mapState(['formEvents', 'defaultGroupLabels', 'selectedValueStream']),
+    ...mapGetters(['namespaceRestApiRequestPath']),
     selectedValueStreamId() {
       return this.selectedValueStream?.id || -1;
     },
@@ -144,49 +141,53 @@ export default {
 
       return { id, message, variant: 'success' };
     },
-  },
-  watch: {
-    createValueStreamErrors: 'refreshErrors',
-  },
-  created() {
-    this.refreshErrors();
+    submitParams() {
+      const { name, stages, isEditing } = this;
+      return {
+        name,
+        stages: formatStageDataForSubmission(stages, isEditing),
+      };
+    },
   },
   methods: {
-    ...mapActions(['createValueStream', 'updateValueStream']),
-    async onSubmit() {
+    onSubmit() {
       this.showSubmitError = false;
       this.validate();
       if (this.hasFormErrors) return;
 
-      let req = this.createValueStream;
-      let params = {
-        name: this.name,
-        stages: formatStageDataForSubmission(this.stages, this.isEditing),
-      };
-      if (this.isEditing) {
-        req = this.updateValueStream;
-        params = {
-          ...params,
-          id: this.initialData.id,
-        };
-      }
-
       this.isSubmitting = true;
 
-      const response = await req(params);
-
-      if (this.hasFormErrors) {
-        this.isSubmitting = false;
-        this.showSubmitError = true;
-        return;
-      }
+      this.submitRequest()
+        .then(({ data: { id } }) => {
+          this.track('submit_form', {
+            label: this.isEditing ? 'edit_value_stream' : 'create_value_stream',
+          });
 
-      this.track('submit_form', {
-        label: this.isEditing ? 'edit_value_stream' : 'create_value_stream',
-      });
+          const redirectPath = mergeUrlParams({ value_stream_id: id }, this.vsaPath);
+          visitUrlWithAlerts(redirectPath, [this.submissionSuccessfulAlert]);
+        })
+        .catch(({ response: { data } }) => {
+          this.isSubmitting = false;
+          this.showSubmitError = true;
 
-      const redirectPath = mergeUrlParams({ value_stream_id: response.data.id }, this.vsaPath);
-      visitUrlWithAlerts(redirectPath, [this.submissionSuccessfulAlert]);
+          const {
+            payload: { errors: { name, stages = {} } = {} },
+          } = data;
+          this.setErrors({
+            name,
+            stages: prepareStageErrors(this.submitParams.stages, stages),
+          });
+        });
+    },
+    submitRequest() {
+      const { isEditing, namespaceRestApiRequestPath, initialData, submitParams } = this;
+      return isEditing
+        ? updateValueStream({
+            namespacePath: namespaceRestApiRequestPath,
+            valueStreamId: initialData.id,
+            data: submitParams,
+          })
+        : createValueStream(namespaceRestApiRequestPath, submitParams);
     },
     stageGroupLabel(index) {
       return sprintf(this.$options.i18n.STAGE_INDEX, { index: index + 1 });
@@ -206,9 +207,8 @@ export default {
         }),
       );
     },
-    refreshErrors() {
-      const { defaultStageConfig, selectedPreset, createValueStreamErrors = {} } = this;
-      const { name = [], stages = [{}] } = createValueStreamErrors;
+    setErrors({ name = [], stages = [{}] }) {
+      const { defaultStageConfig, selectedPreset } = this;
       this.nameErrors = name;
       this.stageErrors =
         cloneDeep(stages) || initializeStageErrors(defaultStageConfig, selectedPreset);
diff --git a/ee/app/assets/javascripts/analytics/cycle_analytics/vsa_settings/utils.js b/ee/app/assets/javascripts/analytics/cycle_analytics/vsa_settings/utils.js
index 362b72ba17539954ca316976d3cbe9c58f3b7f4f..e9dd49ca1165cd51da5e2b69faeb89b056949fe2 100644
--- a/ee/app/assets/javascripts/analytics/cycle_analytics/vsa_settings/utils.js
+++ b/ee/app/assets/javascripts/analytics/cycle_analytics/vsa_settings/utils.js
@@ -1,5 +1,8 @@
 import { isEqual, pick } from 'lodash';
-import { convertObjectPropsToSnakeCase } from '~/lib/utils/common_utils';
+import {
+  convertObjectPropsToCamelCase,
+  convertObjectPropsToSnakeCase,
+} from '~/lib/utils/common_utils';
 import {
   isStartEvent,
   getAllowedEndEvents,
@@ -225,6 +228,19 @@ const prepareDefaultStage = (defaultStageConfig, { name, ...rest }) => {
   };
 };
 
+/**
+ * Prepares the stage errors for use in the create value stream form
+ *
+ * The JSON error response returns a key value pair, the key corresponds to the
+ * index of the stage with errors and the value is the returned error(s)
+ *
+ * @param {Array} stages - Array of value stream stages
+ * @param {Object} errors - Key value pair of stage errors
+ * @returns {Array} Returns and array of stage error objects
+ */
+export const prepareStageErrors = (stages, errors) =>
+  stages.map((_, index) => convertObjectPropsToCamelCase(errors[index]) || {});
+
 const generateHiddenDefaultStages = (defaultStageConfig, stageNames) => {
   // We use the stage name to check for any default stages that might be hidden
   // Currently the default stages can't be renamed
diff --git a/ee/spec/frontend/analytics/cycle_analytics/components/value_stream_select_spec.js b/ee/spec/frontend/analytics/cycle_analytics/components/value_stream_select_spec.js
index a0c05ecf58bcdc35bdff7f92b91b8f9b10e5eb4a..ddf3179a52adff86e5b2afe7f988f5187e3accac 100644
--- a/ee/spec/frontend/analytics/cycle_analytics/components/value_stream_select_spec.js
+++ b/ee/spec/frontend/analytics/cycle_analytics/components/value_stream_select_spec.js
@@ -36,7 +36,6 @@ describe('ValueStreamSelect', () => {
     new Vuex.Store({
       state: {
         isDeletingValueStream: false,
-        createValueStreamErrors: {},
         deleteValueStreamError: null,
         valueStreams: [],
         selectedValueStream: {},
diff --git a/ee/spec/frontend/analytics/cycle_analytics/store/actions/value_streams_spec.js b/ee/spec/frontend/analytics/cycle_analytics/store/actions/value_streams_spec.js
index fb111a343875c766c3907e4881ed585c9c09c491..577074e9460d5c1c142c887267624a5b87cab85f 100644
--- a/ee/spec/frontend/analytics/cycle_analytics/store/actions/value_streams_spec.js
+++ b/ee/spec/frontend/analytics/cycle_analytics/store/actions/value_streams_spec.js
@@ -8,16 +8,8 @@ import { currentGroup } from 'jest/analytics/cycle_analytics/mock_data';
 import { HTTP_STATUS_NOT_FOUND, HTTP_STATUS_OK } from '~/lib/utils/http_status';
 import { allowedStages as stages, endpoints, valueStreams } from '../../mock_data';
 
-const mockStartEventIdentifier = 'issue_first_mentioned_in_commit';
-const mockEndEventIdentifier = 'issue_first_added_to_board';
-const mockEvents = {
-  startEventIdentifier: mockStartEventIdentifier,
-  endEventIdentifier: mockEndEventIdentifier,
-};
-
 stages[0].hidden = true;
 const activeStages = stages.filter(({ hidden }) => !hidden);
-const hiddenStage = stages[0];
 
 const [selectedStage] = activeStages;
 const selectedStageSlug = selectedStage.slug;
@@ -61,112 +53,6 @@ describe('Value Stream Analytics actions / value streams', () => {
     });
   });
 
-  describe('createValueStream', () => {
-    const payload = {
-      name: 'cool value stream',
-      stages: [
-        {
-          ...selectedStage,
-          ...mockEvents,
-          id: null,
-        },
-        { ...hiddenStage, ...mockEvents },
-      ],
-    };
-
-    const createResp = { id: 'new value stream', is_custom: true, ...payload };
-
-    beforeEach(() => {
-      state = { currentGroup };
-    });
-
-    describe('with no errors', () => {
-      beforeEach(() => {
-        mock.onPost(endpoints.valueStreamData).replyOnce(HTTP_STATUS_OK, createResp);
-      });
-
-      it(`commits ${types.REQUEST_CREATE_VALUE_STREAM}`, () => {
-        return testAction(actions.createValueStream, payload, state, [
-          {
-            type: types.REQUEST_CREATE_VALUE_STREAM,
-          },
-        ]);
-      });
-    });
-
-    describe('with errors', () => {
-      const errors = { name: ['is taken'] };
-      const message = { message: 'error' };
-      const resp = { message, payload: { errors } };
-      beforeEach(() => {
-        mock.onPost(endpoints.valueStreamData).replyOnce(HTTP_STATUS_NOT_FOUND, resp);
-      });
-
-      it(`commits the ${types.REQUEST_CREATE_VALUE_STREAM} and ${types.RECEIVE_CREATE_VALUE_STREAM_ERROR} actions `, () => {
-        return testAction(
-          actions.createValueStream,
-          payload,
-          state,
-          [
-            { type: types.REQUEST_CREATE_VALUE_STREAM },
-            {
-              type: types.RECEIVE_CREATE_VALUE_STREAM_ERROR,
-              payload: { message, data: payload, errors },
-            },
-          ],
-          [],
-        );
-      });
-    });
-  });
-
-  describe('updateValueStream', () => {
-    const payload = {
-      name: 'cool value stream',
-      stages: [
-        {
-          ...selectedStage,
-          ...mockEvents,
-          id: 'stage-1',
-        },
-        { ...hiddenStage, ...mockEvents },
-      ],
-    };
-    const updateResp = { id: 'new value stream', is_custom: true, ...payload };
-
-    describe('with no errors', () => {
-      beforeEach(() => {
-        state = { currentGroup };
-        mock.onPut(endpoints.valueStreamData).replyOnce(HTTP_STATUS_OK, updateResp);
-      });
-
-      it(`commits the ${types.REQUEST_UPDATE_VALUE_STREAM} mutation`, () => {
-        return testAction(actions.updateValueStream, payload, state, [
-          { type: types.REQUEST_UPDATE_VALUE_STREAM },
-        ]);
-      });
-    });
-
-    describe('with errors', () => {
-      const errors = { name: ['is taken'] };
-      const message = { message: 'error' };
-      const resp = { message, payload: { errors } };
-      beforeEach(() => {
-        mock.onPut(endpoints.valueStreamData).replyOnce(HTTP_STATUS_NOT_FOUND, resp);
-      });
-
-      it(`commits the ${types.REQUEST_UPDATE_VALUE_STREAM} and ${types.RECEIVE_UPDATE_VALUE_STREAM_ERROR} actions `, () => {
-        return testAction(actions.updateValueStream, payload, state, [
-          { type: types.REQUEST_UPDATE_VALUE_STREAM },
-          {
-            type: types.RECEIVE_UPDATE_VALUE_STREAM_ERROR,
-            payload: { message, data: payload, errors },
-          },
-        ]);
-      });
-    });
-  });
-
   describe('deleteValueStream', () => {
     const payload = 'my-fake-value-stream';
 
diff --git a/ee/spec/frontend/analytics/cycle_analytics/store/mutations_spec.js b/ee/spec/frontend/analytics/cycle_analytics/store/mutations_spec.js
index 37ecab58eaf3f1d6d64b5f600d5ebc0a9ad37bf9..624d4f3112a580497f50ae4f2498106e7cae7aaa 100644
--- a/ee/spec/frontend/analytics/cycle_analytics/store/mutations_spec.js
+++ b/ee/spec/frontend/analytics/cycle_analytics/store/mutations_spec.js
@@ -37,55 +37,40 @@ describe('Value Stream Analytics mutations', () => {
   });
 
   it.each`
-    mutation                                     | stateKey                     | value
-    ${types.REQUEST_VALUE_STREAMS}               | ${'valueStreams'}            | ${[]}
-    ${types.RECEIVE_VALUE_STREAMS_ERROR}         | ${'valueStreams'}            | ${[]}
-    ${types.REQUEST_VALUE_STREAMS}               | ${'isLoadingValueStreams'}   | ${true}
-    ${types.RECEIVE_VALUE_STREAMS_ERROR}         | ${'isLoadingValueStreams'}   | ${false}
-    ${types.REQUEST_STAGE_DATA}                  | ${'isLoadingStage'}          | ${true}
-    ${types.REQUEST_STAGE_DATA}                  | ${'selectedStageEvents'}     | ${[]}
-    ${types.REQUEST_STAGE_DATA}                  | ${'pagination'}              | ${{}}
-    ${types.RECEIVE_STAGE_DATA_ERROR}            | ${'isLoadingStage'}          | ${false}
-    ${types.RECEIVE_STAGE_DATA_ERROR}            | ${'selectedStageEvents'}     | ${[]}
-    ${types.RECEIVE_STAGE_DATA_ERROR}            | ${'pagination'}              | ${{}}
-    ${types.REQUEST_VALUE_STREAM_DATA}           | ${'isLoading'}               | ${true}
-    ${types.RECEIVE_GROUP_STAGES_ERROR}          | ${'stages'}                  | ${[]}
-    ${types.REQUEST_GROUP_STAGES}                | ${'stages'}                  | ${[]}
-    ${types.REQUEST_STAGE_MEDIANS}               | ${'medians'}                 | ${{}}
-    ${types.RECEIVE_STAGE_MEDIANS_ERROR}         | ${'medians'}                 | ${{}}
-    ${types.REQUEST_CREATE_VALUE_STREAM}         | ${'createValueStreamErrors'} | ${{}}
-    ${types.REQUEST_UPDATE_VALUE_STREAM}         | ${'createValueStreamErrors'} | ${{}}
-    ${types.REQUEST_DELETE_VALUE_STREAM}         | ${'isDeletingValueStream'}   | ${true}
-    ${types.RECEIVE_DELETE_VALUE_STREAM_SUCCESS} | ${'isDeletingValueStream'}   | ${false}
-    ${types.REQUEST_DELETE_VALUE_STREAM}         | ${'deleteValueStreamError'}  | ${null}
-    ${types.RECEIVE_DELETE_VALUE_STREAM_SUCCESS} | ${'deleteValueStreamError'}  | ${null}
-    ${types.RECEIVE_DELETE_VALUE_STREAM_SUCCESS} | ${'selectedValueStream'}     | ${null}
-    ${types.RECEIVE_DELETE_VALUE_STREAM_SUCCESS} | ${'stages'}                  | ${[]}
-    ${types.INITIALIZE_VALUE_STREAM_SUCCESS}     | ${'isLoading'}               | ${false}
-    ${types.REQUEST_STAGE_COUNTS}                | ${'stageCounts'}             | ${{}}
-    ${types.RECEIVE_STAGE_COUNTS_ERROR}          | ${'stageCounts'}             | ${{}}
-    ${types.REQUEST_GROUP_LABELS}                | ${'defaultGroupLabels'}      | ${[]}
-    ${types.RECEIVE_GROUP_LABELS_ERROR}          | ${'defaultGroupLabels'}      | ${[]}
-    ${types.SET_STAGE_EVENTS}                    | ${'formEvents'}              | ${[]}
+    mutation                                     | stateKey                    | value
+    ${types.REQUEST_VALUE_STREAMS}               | ${'valueStreams'}           | ${[]}
+    ${types.RECEIVE_VALUE_STREAMS_ERROR}         | ${'valueStreams'}           | ${[]}
+    ${types.REQUEST_VALUE_STREAMS}               | ${'isLoadingValueStreams'}  | ${true}
+    ${types.RECEIVE_VALUE_STREAMS_ERROR}         | ${'isLoadingValueStreams'}  | ${false}
+    ${types.REQUEST_STAGE_DATA}                  | ${'isLoadingStage'}         | ${true}
+    ${types.REQUEST_STAGE_DATA}                  | ${'selectedStageEvents'}    | ${[]}
+    ${types.REQUEST_STAGE_DATA}                  | ${'pagination'}             | ${{}}
+    ${types.RECEIVE_STAGE_DATA_ERROR}            | ${'isLoadingStage'}         | ${false}
+    ${types.RECEIVE_STAGE_DATA_ERROR}            | ${'selectedStageEvents'}    | ${[]}
+    ${types.RECEIVE_STAGE_DATA_ERROR}            | ${'pagination'}             | ${{}}
+    ${types.REQUEST_VALUE_STREAM_DATA}           | ${'isLoading'}              | ${true}
+    ${types.RECEIVE_GROUP_STAGES_ERROR}          | ${'stages'}                 | ${[]}
+    ${types.REQUEST_GROUP_STAGES}                | ${'stages'}                 | ${[]}
+    ${types.REQUEST_STAGE_MEDIANS}               | ${'medians'}                | ${{}}
+    ${types.RECEIVE_STAGE_MEDIANS_ERROR}         | ${'medians'}                | ${{}}
+    ${types.REQUEST_DELETE_VALUE_STREAM}         | ${'isDeletingValueStream'}  | ${true}
+    ${types.RECEIVE_DELETE_VALUE_STREAM_SUCCESS} | ${'isDeletingValueStream'}  | ${false}
+    ${types.REQUEST_DELETE_VALUE_STREAM}         | ${'deleteValueStreamError'} | ${null}
+    ${types.RECEIVE_DELETE_VALUE_STREAM_SUCCESS} | ${'deleteValueStreamError'} | ${null}
+    ${types.RECEIVE_DELETE_VALUE_STREAM_SUCCESS} | ${'selectedValueStream'}    | ${null}
+    ${types.RECEIVE_DELETE_VALUE_STREAM_SUCCESS} | ${'stages'}                 | ${[]}
+    ${types.INITIALIZE_VALUE_STREAM_SUCCESS}     | ${'isLoading'}              | ${false}
+    ${types.REQUEST_STAGE_COUNTS}                | ${'stageCounts'}            | ${{}}
+    ${types.RECEIVE_STAGE_COUNTS_ERROR}          | ${'stageCounts'}            | ${{}}
+    ${types.REQUEST_GROUP_LABELS}                | ${'defaultGroupLabels'}     | ${[]}
+    ${types.RECEIVE_GROUP_LABELS_ERROR}          | ${'defaultGroupLabels'}     | ${[]}
+    ${types.SET_STAGE_EVENTS}                    | ${'formEvents'}             | ${[]}
   `('$mutation will set $stateKey=$value', ({ mutation, stateKey, value }) => {
     mutations[mutation](state);
 
     expect(state[stateKey]).toEqual(value);
   });
 
-  const valueStreamErrors = {
-    data: { stages },
-    errors: {
-      name: ['is required'],
-      stages: { 1: { name: "Can't be blank" } },
-    },
-  };
-
-  const expectedValueStreamErrors = {
-    name: ['is required'],
-    stages: [{}, { name: "Can't be blank" }, {}, {}, {}, {}, {}, {}],
-  };
-
   const pagination = { page: 10, hasNextPage: true, sort: null, direction: null };
 
   it.each`
@@ -94,8 +79,6 @@ describe('Value Stream Analytics mutations', () => {
     ${types.SET_DATE_RANGE}                    | ${{ createdAfter, createdBefore }}                       | ${{ createdAfter, createdBefore }}
     ${types.SET_PREDEFINED_DATE_RANGE}         | ${predefinedDateRange}                                   | ${{ predefinedDateRange }}
     ${types.SET_SELECTED_STAGE}                | ${{ id: 'first-stage' }}                                 | ${{ selectedStage: { id: 'first-stage' } }}
-    ${types.RECEIVE_CREATE_VALUE_STREAM_ERROR} | ${valueStreamErrors}                                     | ${{ createValueStreamErrors: expectedValueStreamErrors }}
-    ${types.RECEIVE_UPDATE_VALUE_STREAM_ERROR} | ${valueStreamErrors}                                     | ${{ createValueStreamErrors: expectedValueStreamErrors }}
     ${types.RECEIVE_DELETE_VALUE_STREAM_ERROR} | ${'Some error occurred'}                                 | ${{ deleteValueStreamError: 'Some error occurred' }}
     ${types.RECEIVE_VALUE_STREAMS_SUCCESS}     | ${valueStreams}                                          | ${{ valueStreams, isLoadingValueStreams: false }}
     ${types.SET_SELECTED_VALUE_STREAM}         | ${valueStreams[1].id}                                    | ${{ selectedValueStream: {} }}
diff --git a/ee/spec/frontend/analytics/cycle_analytics/utils_spec.js b/ee/spec/frontend/analytics/cycle_analytics/utils_spec.js
index a92627ec7282ac5760cb3347e6fc7c406527e54e..bd5dad9a520fd85eaf544b399cb29ee3f9152fe6 100644
--- a/ee/spec/frontend/analytics/cycle_analytics/utils_spec.js
+++ b/ee/spec/frontend/analytics/cycle_analytics/utils_spec.js
@@ -14,7 +14,6 @@ import {
   flattenTaskByTypeSeries,
   orderByDate,
   toggleSelectedLabel,
-  prepareStageErrors,
   formatMedianValues,
   generateFilterTextDescription,
   groupDurationsByDay,
@@ -330,29 +329,6 @@ describe('Value Stream Analytics utils', () => {
     });
   });
 
-  describe('prepareStageErrors', () => {
-    const stages = [{ name: 'stage 1' }, { name: 'stage 2' }, { name: 'stage 3' }];
-    const nameError = { name: "Can't be blank" };
-    const stageErrors = { 1: nameError };
-
-    it('returns an object for each stage', () => {
-      const res = prepareStageErrors(stages, stageErrors);
-      expect(res[0]).toEqual({});
-      expect(res[1]).toEqual(nameError);
-      expect(res[2]).toEqual({});
-    });
-
-    it('returns the same number of error objects as stages', () => {
-      const res = prepareStageErrors(stages, stageErrors);
-      expect(res).toHaveLength(stages.length);
-    });
-
-    it('returns an empty object for each stage if there are no errors', () => {
-      const res = prepareStageErrors(stages, {});
-      expect(res).toEqual([{}, {}, {}]);
-    });
-  });
-
   describe('flattenTaskByTypeSeries', () => {
     const dummySeries = Object.fromEntries([
       ['2019-01-16', 40],
diff --git a/ee/spec/frontend/analytics/cycle_analytics/vsa_settings/components/value_stream_form_content_spec.js b/ee/spec/frontend/analytics/cycle_analytics/vsa_settings/components/value_stream_form_content_spec.js
index 93490f4a92574fea70b6a7bcbc15292ee9c24413..97b6364b5f4fbb242097e9cb4f789e5689907a5c 100644
--- a/ee/spec/frontend/analytics/cycle_analytics/vsa_settings/components/value_stream_form_content_spec.js
+++ b/ee/spec/frontend/analytics/cycle_analytics/vsa_settings/components/value_stream_form_content_spec.js
@@ -2,8 +2,11 @@ import { GlAlert } from '@gitlab/ui';
 import Vue, { nextTick } from 'vue';
 // eslint-disable-next-line no-restricted-imports
 import Vuex from 'vuex';
+import axios from 'axios';
+import MockAdapter from 'axios-mock-adapter';
 import CrudComponent from '~/vue_shared/components/crud_component.vue';
 import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
+import waitForPromises from 'helpers/wait_for_promises';
 import {
   PRESET_OPTIONS_BLANK,
   PRESET_OPTIONS_DEFAULT,
@@ -12,6 +15,7 @@ import CustomStageFields from 'ee/analytics/cycle_analytics/vsa_settings/compone
 import DefaultStageFields from 'ee/analytics/cycle_analytics/vsa_settings/components/default_stage_fields.vue';
 import ValueStreamFormContent from 'ee/analytics/cycle_analytics/vsa_settings/components/value_stream_form_content.vue';
 import { mockTracking, unmockTracking } from 'helpers/tracking_helper';
+import { HTTP_STATUS_OK, HTTP_STATUS_NOT_FOUND } from '~/lib/utils/http_status';
 import { visitUrlWithAlerts } from '~/lib/utils/url_utility';
 import {
   convertObjectPropsToCamelCase,
@@ -23,6 +27,7 @@ import {
   defaultStageConfig,
   rawCustomStage,
   groupLabels as defaultGroupLabels,
+  endpoints,
 } from '../../mock_data';
 
 jest.mock('~/lib/utils/url_utility', () => ({
@@ -33,12 +38,12 @@ jest.mock('~/lib/utils/url_utility', () => ({
 Vue.use(Vuex);
 
 describe('ValueStreamFormContent', () => {
+  let mock;
   let wrapper = null;
   let trackingSpy = null;
 
   const mockValueStream = { id: 13 };
-  const createValueStreamMock = jest.fn(() => Promise.resolve({ data: mockValueStream }));
-  const updateValueStreamMock = jest.fn(() => Promise.resolve({ data: mockValueStream }));
+  const namespacePath = 'fake/group/path';
   const streamName = 'Cool stream';
   const formSubmissionErrors = {
     name: ['has already been taken'],
@@ -50,8 +55,8 @@ describe('ValueStreamFormContent', () => {
   };
 
   const initialData = {
+    ...mockValueStream,
     stages: [convertObjectPropsToCamelCase(rawCustomStage)],
-    id: 1337,
     name: 'Editable value stream',
   };
 
@@ -60,18 +65,11 @@ describe('ValueStreamFormContent', () => {
       state: {
         formEvents,
         defaultGroupLabels,
-        createValueStreamErrors: {},
         selectedValueStream: undefined,
         ...stateOverrides,
       },
-      mutations: {
-        setCreateValueStreamErrors(state, value) {
-          state.createValueStreamErrors = value;
-        },
-      },
-      actions: {
-        createValueStream: createValueStreamMock,
-        updateValueStream: updateValueStreamMock,
+      getters: {
+        namespaceRestApiRequestPath: () => namespacePath,
       },
     });
 
@@ -115,6 +113,14 @@ describe('ValueStreamFormContent', () => {
     findPresetSelector().vm.$emit('input', PRESET_OPTIONS_DEFAULT);
   const changeToCustomStages = () => findPresetSelector().vm.$emit('input', PRESET_OPTIONS_BLANK);
 
+  beforeEach(() => {
+    mock = new MockAdapter(axios);
+  });
+
+  afterEach(() => {
+    mock.restore();
+  });
+
   describe('when creating value stream', () => {
     beforeEach(() => {
       wrapper = createComponent({ state: { defaultGroupLabels: null } });
@@ -243,47 +249,6 @@ describe('ValueStreamFormContent', () => {
       });
     });
 
-    describe('initial form stage errors', () => {
-      const createValueStreamErrors = {
-        stages: [
-          {
-            name: ['Name field is required'],
-            startEventIdentifier: ['Start event is required'],
-          },
-        ],
-      };
-
-      beforeEach(() => {
-        wrapper = createComponent({
-          state: { createValueStreamErrors },
-        });
-      });
-
-      it('renders errors for a default stage field', () => {
-        expect(findDefaultStages().at(0).props().errors).toEqual(createValueStreamErrors.stages[0]);
-      });
-    });
-
-    describe('initial form name errors', () => {
-      const nameError = 'Name field required';
-
-      beforeEach(() => {
-        wrapper = createComponent({
-          state: {
-            createValueStreamErrors: { name: [nameError] },
-          },
-        });
-      });
-
-      it('sets the feedback for the name form group', () => {
-        expect(findNameFormGroup().attributes('invalid-feedback')).toBe(nameError);
-      });
-
-      it('sets the state for the name input', () => {
-        expect(findNameInput().props().state).toBe(false);
-      });
-    });
-
     describe('with valid fields', () => {
       beforeEach(() => {
         trackingSpy = mockTracking(undefined, wrapper.element, jest.spyOn);
@@ -295,14 +260,18 @@ describe('ValueStreamFormContent', () => {
 
       describe('form submitted successfully', () => {
         beforeEach(async () => {
+          mock.onPost(endpoints.valueStreamData).replyOnce(HTTP_STATUS_OK, mockValueStream);
           wrapper = createComponent();
 
           await findNameInput().vm.$emit('input', streamName);
           clickSubmit();
+
+          await waitForPromises();
         });
 
-        it('calls the "createValueStream" event when submitted', () => {
-          expect(createValueStreamMock).toHaveBeenCalledWith(expect.any(Object), {
+        it('sends a create request', () => {
+          expect(mock.history.post).toHaveLength(1);
+          expect(JSON.parse(mock.history.post[0].data)).toEqual({
             name: streamName,
             stages: [
               {
@@ -344,16 +313,20 @@ describe('ValueStreamFormContent', () => {
 
       describe('form submission fails', () => {
         beforeEach(async () => {
+          mock.onPost(endpoints.valueStreamData).replyOnce(HTTP_STATUS_NOT_FOUND, {
+            payload: { errors: formSubmissionErrors },
+          });
+
           wrapper = createComponent();
 
           await findNameInput().vm.$emit('input', streamName);
           clickSubmit();
 
-          wrapper.vm.$store.commit('setCreateValueStreamErrors', formSubmissionErrors);
+          await waitForPromises();
         });
 
-        it('calls the createValueStream action', () => {
-          expect(createValueStreamMock).toHaveBeenCalled();
+        it('sends a create request', () => {
+          expect(mock.history.post).toHaveLength(1);
         });
 
         it('does not clear the name field', () => {
@@ -523,6 +496,8 @@ describe('ValueStreamFormContent', () => {
 
       describe('form submitted successfully', () => {
         beforeEach(() => {
+          mock.onPut(endpoints.valueStreamData).replyOnce(HTTP_STATUS_OK, mockValueStream);
+
           wrapper = createComponent({
             props: {
               initialData,
@@ -534,11 +509,16 @@ describe('ValueStreamFormContent', () => {
           });
 
           clickSubmit();
+          return waitForPromises();
         });
 
-        it('calls the "updateValueStreamMock" event when submitted', () => {
-          expect(updateValueStreamMock).toHaveBeenCalledWith(expect.any(Object), {
-            ...initialData,
+        it('sends an update request', () => {
+          expect(mock.history.put).toHaveLength(1);
+          expect(mock.history.put[0].url).toBe(
+            '/fake/group/path/-/analytics/value_stream_analytics/value_streams/13',
+          );
+          expect(JSON.parse(mock.history.put[0].data)).toEqual({
+            name: initialData.name,
             stages: initialData.stages.map((stage) =>
               convertObjectPropsToSnakeCase(stage, { deep: true }),
             ),
@@ -568,6 +548,10 @@ describe('ValueStreamFormContent', () => {
 
       describe('form submission fails', () => {
         beforeEach(() => {
+          mock.onPut(endpoints.valueStreamData).replyOnce(HTTP_STATUS_NOT_FOUND, {
+            payload: { errors: formSubmissionErrors },
+          });
+
           wrapper = createComponent({
             props: {
               initialData,
@@ -579,11 +563,11 @@ describe('ValueStreamFormContent', () => {
           });
 
           clickSubmit();
-          wrapper.vm.$store.commit('setCreateValueStreamErrors', formSubmissionErrors);
+          return waitForPromises();
         });
 
-        it('calls the updateValueStreamMock action', () => {
-          expect(updateValueStreamMock).toHaveBeenCalled();
+        it('sends an update request', () => {
+          expect(mock.history.put).toHaveLength(1);
         });
 
         it('does not clear the name field', () => {
diff --git a/ee/spec/frontend/analytics/cycle_analytics/vsa_settings/utils_spec.js b/ee/spec/frontend/analytics/cycle_analytics/vsa_settings/utils_spec.js
index acca6a1571c24d00fea0e6962d895629e4dc9ff5..5716d97e14cd6110cd689a9c4ffe8d0910664985 100644
--- a/ee/spec/frontend/analytics/cycle_analytics/vsa_settings/utils_spec.js
+++ b/ee/spec/frontend/analytics/cycle_analytics/vsa_settings/utils_spec.js
@@ -10,6 +10,7 @@ import {
   formatStageDataForSubmission,
   generateInitialStageData,
   cleanStageName,
+  prepareStageErrors,
 } from 'ee/analytics/cycle_analytics/vsa_settings/utils';
 import { labelStartEvent, labelEndEvent } from 'ee_jest/analytics/cycle_analytics/mock_data';
 
@@ -301,3 +302,21 @@ describe('generateInitialStageData', () => {
     });
   });
 });
+
+describe('prepareStageErrors', () => {
+  const stages = [{ name: 'stage 1' }, { name: 'stage 2' }, { name: 'stage 3' }];
+  const nameError = { name: "Can't be blank" };
+  const stageErrors = { 1: nameError };
+
+  it('returns an object for each stage', () => {
+    expect(prepareStageErrors(stages, stageErrors)).toEqual([{}, nameError, {}]);
+  });
+
+  it('returns the same number of error objects as stages', () => {
+    expect(prepareStageErrors(stages, stageErrors)).toHaveLength(stages.length);
+  });
+
+  it('returns an empty object for each stage if there are no errors', () => {
+    expect(prepareStageErrors(stages, {})).toEqual([{}, {}, {}]);
+  });
+});