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
- Re-check the config is schema-valid for the target service, then retry save
- Verify the config editor service for serviceTarget is running and writable
- Re-authenticate if the token expired between validate and save
- 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
- Always run validate before save and block save on failure
- Preserve the user's edited config on failure for retry
- Re-authenticate on 401-like codes before surfacing save failed
- Monitor backend save endpoint errors via logs
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
- errors.loadFailed
- errors.validateFailed
- InvalidModel
- VideoUploadVidNotFound
- DashScope task id is missing
AI-assisted analysis of yikart/AiToEarn@d3aa8bea5b (2026-08-31).
Data as JSON: /api/errors/bcaa2f1c913af36c.
Report an issue: GitHub.