yikart/AiToEarn · error · Error

errors.saveFailed

Error message

errors.saveFailed

What it means

ConfigManagerDialog's save handler throws this fallback Error when saveConfigEditorConfigApi returns a non-zero code or an empty response without a backend message. The error is caught and surfaced via setError; the new config is not persisted and UI state is not updated.

Source

Thrown at project/aitoearn-web/src/app/layout/ConfigManagerDialog/index.tsx:508

  const saveConfig = useCallback(async (action: LoadingAction = 'save') => {
    const editableConfig = getEditableConfig()
    if (!editableConfig)
      return false
    const submittableConfig = stripInsertedRelayPlaceholder(editableConfig, insertedRelayPath, serviceTarget)

    setLoadingAction(action)
    setError(null)
    setSuccessMessage('')

    try {
      const valid = await validateConfig(action, editableConfig)
      if (!valid)
        return false

      const response = await saveConfigEditorConfigApi({ config: submittableConfig }, serviceTarget, true)
      if (!response || response.code !== 0) {
        throw new Error(getResponseMessage(response) || t('errors.saveFailed'))
      }

      const normalizedConfig = ensureRelayConfig(submittableConfig, serviceTarget)
      setConfig(normalizedConfig.config)
      setOriginalConfig(normalizedConfig.config)
      setJsonText(formatJsonConfig(normalizedConfig.config))
      setInsertedRelayPath(normalizedConfig.insertedRelayPath)
      if (action === 'save') {
        setSuccessMessage(t('messages.saveSuccess'))
        toast.success(t('messages.saveSuccess'))
      }
      return true
    }
    catch (saveError) {
      setError({ title: t('errors.saveFailed'), description: getErrorMessage(saveError) })
      return false
    }
    finally {

View on GitHub (pinned to d3aa8bea5b)

Solutions

  1. Re-check the config is schema-valid for the target service, then retry save
  2. Verify the config editor service for serviceTarget is running and writable
  3. Re-authenticate if the token expired between validate and save
  4. Check backend logs for the save endpoint failure reason

Example fix

// before
if (!response || response.code !== 0) {
  throw new Error(getResponseMessage(response) || t('errors.saveFailed'))
}
// after
if (!response || response.code !== 0) {
  setError(getResponseMessage(response) || t('errors.saveFailed'))
  return false
}
Defensive patterns

Strategy: try-catch

Validate before calling

await validateConfigEditorConfigApi({ config }, serviceTarget, true) // must return code === 0 before saving

Try / catch

try {
  const response = await saveConfigEditorConfigApi({ config }, serviceTarget, true)
  if (!response || response.code !== 0)
    throw new Error(getResponseMessage(response) || 'save failed')
} catch (e) {
  setError(e instanceof Error ? e.message : 'save failed')
  // keep editor state so user can retry without losing edits
}

Prevention

When it happens

Trigger: Calling saveConfigEditorConfigApi({ config: submittableConfig }, serviceTarget, true) after successful local validation, and receiving response === null/undefined or response.code !== 0 with no message.

Common situations: Concurrent edit conflict on the remote config; config editor service down for the target; write permission denied by backend; oversized or schema-invalid config payload; token expired between validate and save.

Related errors


AI-assisted analysis of yikart/AiToEarn@d3aa8bea5b (2026-08-31). Data as JSON: /api/errors/bcaa2f1c913af36c. Report an issue: GitHub.