---
name: resolve_obsidian_embed
kind: function
lang: py
domain: obsidian
version: "1.0.0"
purity: impure
signature: "def resolve_obsidian_embed(vault_dir: str, embed_name: str) -> str"
description: "Resuelve el path absoluto real de un attachment embebido buscandolo por nombre dentro de un vault de Obsidian. Obsidian resuelve los embeds ![[...]] por nombre de archivo unico (no por path), asi que esta funcion recorre el vault recursivamente (una pasada con os.walk) y devuelve el primer archivo cuyo basename coincida (case-insensitive), excluyendo .obsidian/ y .trash/. Si el embed no trae extension, acepta cualquier match de ese basename. Devuelve cadena vacia si no existe (NO lanza). Lanza si vault_dir no existe. No depende de la app GUI."
tags: [obsidian, embed, attachment, resolve, filesystem, migrate]
uses_functions: []
uses_types: []
returns: []
returns_optional: false
error_type: "error_go_core"
imports: ["os"]
params:
  - name: vault_dir
    desc: "ruta a la raiz del vault Obsidian donde buscar el attachment"
  - name: embed_name
    desc: "nombre del attachment embebido (el target de un ![[...]], lo que devuelve extract_obsidian_embeds), con o sin extension"
output: "string con el path absoluto del primer archivo del vault cuyo basename coincide (case-insensitive) con embed_name, o cadena vacia '' si ningun archivo coincide. Excluye .obsidian/ y .trash/."
tested: true
tests:
  - "match exacto en subcarpeta"
  - "match case insensitive"
  - "sin extension acepta cualquier match"
  - "no existe devuelve vacio"
  - "excluye obsidian y trash"
  - "vault inexistente lanza"
test_file_path: "python/functions/obsidian/resolve_obsidian_embed_test.py"
file_path: "python/functions/obsidian/resolve_obsidian_embed.py"
---

## Ejemplo

```python
import sys, os
sys.path.insert(0, os.path.join("python", "functions"))
from obsidian import extract_obsidian_embeds, resolve_obsidian_embed

body = "Mi DNI: ![[dni enmanuel (2).jpg]]"
for embed in extract_obsidian_embeds(body):
    path = resolve_obsidian_embed("/home/me/MiVault", embed)
    print(embed, "->", path or "(no encontrado)")
# dni enmanuel (2).jpg -> /home/me/MiVault/attachments/dni enmanuel (2).jpg
```

## Cuando usarla

Usala junto a `extract_obsidian_embeds` cuando migres o extraigas un subgrafo de
notas y necesites el path fisico real de cada attachment para copiarlo al nuevo
destino. Replica la resolucion por-nombre de Obsidian sin abrir la app GUI:
basta con el directorio del vault en disco.

## Gotchas

- **Resuelve por NOMBRE de archivo, no por path.** Igual que Obsidian: busca el
  basename en TODO el vault. Si hay dos archivos con el mismo nombre en carpetas
  distintas (`fotos/logo.png` y `assets/logo.png`), devuelve el PRIMERO que
  encuentra `os.walk` — el orden de `os.walk` no esta garantizado entre sistemas,
  asi que con nombres duplicados el resultado puede no ser el embed que Obsidian
  mostraria. Para vaults con nombres ambiguos, deduplica los nombres antes de
  migrar.
- Si el embed no existe en el vault devuelve `""` (cadena vacia), NO lanza
  excepcion. Comprueba el valor antes de usarlo como ruta.
- SI lanza `FileNotFoundError` / `NotADirectoryError` si `vault_dir` no existe o
  no es un directorio.
- Es impura: recorre el filesystem en cada llamada. Si vas a resolver muchos
  embeds del mismo vault, considera construir tu propio indice `basename -> path`
  con un unico `os.walk` en lugar de llamar a esta funcion en bucle.
