{"record":{"id":"12302c9f5d99b943","repo":"eyaltoledano/claude-task-master","slug":"failed-to-save-workflow-state-error-message","errorCode":null,"errorMessage":"Failed to save workflow state: ${error.message}","messagePattern":"Failed to save workflow state: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"packages/tm-core/src/modules/workflow/managers/workflow-state-manager.ts","lineNumber":152,"sourceCode":"\t\t\tawait this.ensureWriter();\n\n\t\t\t// Serialize and validate JSON\n\t\t\tconst jsonContent = JSON.stringify(state, null, 2);\n\n\t\t\t// Validate that the JSON is well-formed by parsing it back\n\t\t\ttry {\n\t\t\t\tJSON.parse(jsonContent);\n\t\t\t} catch (parseError) {\n\t\t\t\tthis.logger.error('Generated invalid JSON:', jsonContent);\n\t\t\t\tthrow new Error('Failed to generate valid JSON from workflow state');\n\t\t\t}\n\n\t\t\t// Write using steno (handles queuing and atomic writes automatically)\n\t\t\tawait this.writer!.write(jsonContent + '\\n');\n\n\t\t\tthis.logger.debug(`Saved workflow state (${jsonContent.length} bytes)`);\n\t\t} catch (error: any) {\n\t\t\tthrow new Error(`Failed to save workflow state: ${error.message}`);\n\t\t}\n\t}\n\n\t/**\n\t * Create a backup of current state\n\t */\n\tasync createBackup(): Promise<void> {\n\t\ttry {\n\t\t\tconst exists = await this.exists();\n\t\t\tif (!exists) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst state = await this.load();\n\t\t\tawait fs.mkdir(this.backupDir, { recursive: true });\n\n\t\t\tconst timestamp = new Date().toISOString().replace(/[:.]/g, '-');\n\t\t\tconst backupPath = path.join(","sourceCodeStart":134,"sourceCodeEnd":170,"githubUrl":"https://github.com/eyaltoledano/claude-task-master/blob/c0c98d367c55296bfe69e65680625b6db437af02/packages/tm-core/src/modules/workflow/managers/workflow-state-manager.ts#L134-L170","documentation":"This is the catch-all wrapper around WorkflowStateManager.save(). Any failure during serialization, validation, or the steno atomic file write is rethrown as 'Failed to save workflow state: <cause>'. The original error message is preserved after the colon, so read it to find the root cause (disk full, permissions, invalid JSON).","triggerScenarios":"Any save() call (also via startWorkflow, resumeWorkflow, restoreBackup) where JSON.stringify/parse fails or this.writer.write() rejects — e.g. the state directory is read-only, disk is full, or steno write throws.","commonSituations":"Read-only filesystem or wrong permissions on the workflow state path; ENOSPC on a full disk; state file locked by another process; invalid JSON from non-serializable state (error 240's cause wrapped here).","solutions":["Read the cause text after 'Failed to save workflow state:' to identify the underlying error.","Check filesystem permissions and free disk space on the directory containing the state file.","Verify the state object is JSON-serializable (no circular refs/BigInt).","Ensure the state directory exists and the process has write access; create it manually if missing.","Retry if the failure was transient (e.g. temporary EBUSY/EPERM during sync tooling)."],"exampleFix":"// before\nawait manager.save(state); // throws opaque wrapped error\n// after\ntry {\n  await manager.save(state);\n} catch (e) {\n  console.error('root cause:', e.message); // e.g. EACCES: permission denied\n  fs.mkdirSync(path.dirname(statePath), { recursive: true });\n  await manager.save(state);\n}","handlingStrategy":"try-catch","validationCode":"import { accessSync, constants, mkdirSync } from 'fs';\nconst dir = path.dirname(statePath);\ntry { accessSync(dir, constants.W_OK); } catch { mkdirSync(dir, { recursive: true }); }","typeGuard":"null","tryCatchPattern":"try {\n  await manager.save(state);\n} catch (e) {\n  const cause = e.message.replace('Failed to save workflow state: ', '');\n  if (/EACCES|EPERM/.test(cause)) fixPermissions(dir);\n  else if (/ENOSPC/.test(cause)) freeDiskSpace();\n  else if (/invalid JSON/.test(cause)) sanitizeState(state);\n  throw e;\n}","preventionTips":["Verify write access to the state directory at startup","Monitor disk space on volumes holding state files","Keep state JSON-serializable","Wrap save calls at a higher level with one retry after fixing environment"],"tags":["filesystem","persistence","workflow"],"backgroundTag":"state-write-failed","analyzedSha":"c0c98d367c55296bfe69e65680625b6db437af02","analyzedAt":"2026-08-29T02:56:26.071Z","schemaVersion":2},"datasetVersion":"2026-08-29T07:17:48.351Z"}