siyuan-note/siyuan · error

invalid image operation state

Error message

invalid image operation state

What it means

saveImageOperationRecord validates the state argument after computing the asset path: only imageOperationStateRunning and imageOperationStateCompleted are accepted. This error is returned when a caller tries to persist an operation record with a state value outside that enumerated set, so unknown or future state strings cannot corrupt the persisted operation history.

Source

Thrown at kernel/mcp/tools/image.go:290

	if record.AssetPath != "" && !imageOperationAssetExists(record.DocumentID, record.AssetPath) {
		removeImageOperationRecord(key)
		return CallToolResult{}, false
	}
	return record.Result, true
}

func saveImageOperationRecord(key string, meta imageOperationMeta, state string, result CallToolResult) error {
	if !validImageOperationKey(key) {
		return errors.New("invalid image operation key")
	}
	assetPath := meta.AssetPath
	if state == imageOperationStateCompleted {
		if resultPath := imageResultAssetPath(result); resultPath != "" {
			assetPath = resultPath
		}
	}
	if state != imageOperationStateRunning && state != imageOperationStateCompleted {
		return errors.New("invalid image operation state")
	}
	record := imageOperationRecord{
		Version: 1, CreatedAt: time.Now().UnixMilli(), State: state, Action: meta.Action, DocumentID: meta.DocumentID,
		AssetPath: assetPath, Result: result,
	}
	data, err := json.Marshal(record)
	if err != nil {
		return err
	}
	path := imageOperationRecordPath(key)
	if err = os.MkdirAll(filepath.Dir(path), 0755); err != nil {
		return err
	}
	return filelock.WriteFile(path, data)
}

func removeImageOperationRecord(key string) {
	if !validImageOperationKey(key) {

View on GitHub (pinned to 8641553a1f)

Solutions

  1. Pass only imageOperationStateRunning or imageOperationStateCompleted to saveImageOperationRecord
  2. If a new lifecycle state is needed, add it to this validation and to the record schema (bump record Version) deliberately
  3. Check the call site for a typo or swapped constant when this error appears during development
  4. Route failure outcomes through the error/result path instead of inventing a 'failed' state record

Example fix

// before
saveImageOperationRecord(key, meta, "failed", errResult)
// after
saveImageOperationRecord(key, meta, imageOperationStateCompleted, errResult) // failures are recorded as completed with an error result
Defensive patterns

Strategy: type-guard

Validate before calling

const VALID_STATES = ['running', 'completed'];
if (!VALID_STATES.includes(state)) throw new Error(`unsupported operation state: ${state}`);

Type guard

const isImageOpState = (s) => s === 'running' || s === 'completed';

Prevention

When it happens

Trigger: runImageOperation (or the test TestRunImageOperationBlocksUnknownPendingOperation) passes a state string other than 'running' or 'completed' — e.g. a typo like 'runnning', 'failed' (handled via a different path), or an empty state variable.

Common situations: A code change introduces a new state (e.g. 'cancelled') without adding it to this validation; a refactor renames the constants at one call site; a caller passes a state derived from an unvalidated external input.

Understand the failure class

Background: Invalid enum value errors: "Unknown type", "Invalid scope", "must be one of" — when a string is not on the library's allowed list — this error's family across 23 libraries.

Related errors


AI-assisted analysis of siyuan-note/siyuan@8641553a1f (2026-09-11). Data as JSON: /api/errors/dc02b0ce7bf9f99e. Report an issue: GitHub.