siyuan-note/siyuan · error

invalid OCR mapping index

Error message

invalid OCR mapping index

What it means

AssetTextRelinkPlan.Save validates each index in the selected slice against the plan's Results slice before applying it. An index outside [0, len(Results)-1] means the caller is referencing a mapping that does not exist in the plan produced by PrepareAssetTextRelinks, so Save aborts with "invalid OCR mapping index" instead of panicking.

Solutions

  1. Ensure selected indices come from the same plan returned by PrepareAssetTextRelinks and satisfy 0 <= i < len(plan.Results).
  2. Check that the mappings slice passed to PrepareAssetTextRelinks was non-empty before selecting index 0.
  3. Clamp or filter the selected slice: keep only indices within range before calling Save.
  4. If indices came from a previous plan, rebuild them from the current plan's Results.

Example fix

// before
plan, _ := util.PrepareAssetTextRelinks(mappings)
plan.Save(historyDir, []int{0}) // panics-free but errors if mappings is empty
// after
var selected []int
for i := range plan.Results {
    if plan.Results[i].Reason == "" && plan.Results[i].Changed {
        selected = append(selected, i)
    }
}
plan.Save(historyDir, selected)
Defensive patterns

Strategy: validation

Validate before calling

func validIndices(plan *util.AssetTextRelinkPlan, selected []int) bool {
    for _, i := range selected {
        if i < 0 || i >= len(plan.Results) {
            return false
        }
    }
    return true
}

Try / catch

if changed, err := plan.Save(historyDir, selected); err != nil && err.Error() == "invalid OCR mapping index" {
    // rebuild selected from plan.Results and retry once
}

Prevention

When it happens

Trigger: Calling plan.Save(historyDir, selected) with a negative index, an index >= the number of mappings passed to PrepareAssetTextRelinks, or indices from a different/stale plan object than the one whose Results slice is being indexed.

Common situations: Hard-coded indices like []int{0} reused with an empty mappings slice; building a selected list from user checkboxes without clamping after the mapping list changed size; reusing indices captured from an earlier plan after re-running PrepareAssetTextRelinks with fewer mappings.

Related errors


AI-assisted analysis of siyuan-note/siyuan@9f775e8a12 (2026-09-19). Data as JSON: /api/errors/a5047b7e1a4660fd. Report an issue: GitHub.

Appendix: source

Thrown at kernel/util/ocr_relink_batch.go:126

		for _, i := range group {
			conflict = conflict || p.values[i] != p.values[group[0]]
		}
		if conflict {
			for _, i := range group {
				p.Results[i].Reason = "ocr_target_conflict"
			}
		}
	}
	return p, nil
}

// Save 将通过预检的映射合并为一次保存,保留源键;同值重试不生成历史或写入文件。
func (p *AssetTextRelinkPlan) Save(historyDir string, selected []int) ([]int, error) {
	var changed []int
	texts := maps.Clone(p.texts)
	for _, i := range selected {
		if i < 0 || i >= len(p.Results) {
			return nil, errors.New("invalid OCR mapping index")
		}
		result := p.Results[i]
		if result.Reason != "" {
			return nil, errors.New(result.Reason)
		}
		if !result.Changed {
			continue
		}
		texts[(&url.URL{Path: p.mappings[i].NewPath}).EscapedPath()] = p.values[i]
		changed = append(changed, i)
	}
	if len(changed) == 0 {
		return nil, nil
	}
	assetsTextsLock.Lock()
	defer assetsTextsLock.Unlock()
	if !maps.Equal(p.memory, assetsTexts) {
		return nil, errors.New("OCR metadata changed during asset relink")

View on GitHub (pinned to 9f775e8a12)