Berk Akademi
Ana Sayfa
ÖZEL KODLAMA DERSLERİ
Yazılım Özel Ders
Tüm birebir programlara genel bakış
Python Yazılım Kursu
Sıfırdan ileri seviyeye birebir Python
Java Yazılım Kursu
OOP odaklı birebir Java eğitimi
AP Computer Science Principles
AP CSP sınav hazırlığı
GRUP DERSLERİ
Python & Django Masterclass
SINIRLI KONTENJAN
Java & Spring Boot Masterclass
SINIRLI KONTENJAN
C# .NET Masterclass
SINIRLI KONTENJAN
VİDEO DERSLER
Sıfırdan Temel Python Kursu
Kendi Hızında Öğren
ÜCRETSİZ
Seviye Testi
Ücretsiz — Python, Java, algoritma seviye testleri
Kariyerini Keşfet
Sertifika Doğrula
Belge numarası ve soyad ile doğrulama

Python Traceback Nasıl Okunur ve Hata Kaynağı Nasıl Bulunur?

python-traceback-nasil-okunur-hata-kaynagi-bulma
Bu yazıda neler var?
  1. Traceback’i Okumanın Kısa Cevabı: Nereden Başlamalısınız?
  2. Traceback İçindeki Dosya, Satır, Fonksiyon ve Exception Bilgilerini Ayırma
  3. Beş Adımlı Traceback Teşhis Yöntemi
  4. Fonksiyon Çağrı Zinciri İçeren Hatalı Örnek Üzerinden Teşhis
  5. SyntaxError, NameError, TypeError ve KeyError Traceback’te Nasıl Ayırt Edilir?
  6. Sadece Son Satırı Aratmak Neden Yetmez?
  7. Traceback Okuma Pratiği İçin Uygulanabilir Kontrol Listesi
  8. Sık Sorulan Sorular

Python traceback, bir hatanın yalnızca son mesajını değil, hataya gelene kadar izlenen çağrı zincirini de gösterir. Okumaya genellikle en alttaki exception türü ve mesajından başlanır; ardından işaretlenen dosya, satır ve kod incelenir, son olarak çağrı zinciri yukarı doğru takip edilerek hataya yanlış verinin veya varsayımın nerede taşındığı araştırılır.

“Traceback (most recent call last)” ifadesi, çağrıların en güncel olanının çıktının sonlarına yakın gösterildiğini anlatır. Bu nedenle en alt satır önemli bir başlangıç noktasıdır; ancak gerçek kök neden her zaman o satırda bulunmayabilir. Bu bölümde dosya adı, satır numarası, fonksiyon, exception türü ve değişken değerlerini birbirinden ayırarak Python hata mesajını sistemli biçimde okumayı ele alacağız.

Traceback’i Okumanın Kısa Cevabı: Nereden Başlamalısınız?

Bir traceback gördüğünüzde önce en alt satıra bakın. Burada genellikle exception sınıfı ve hatayı açıklayan mesaj bulunur. Örneğin NameError, tanınmayan bir isim kullanıldığını; TypeError, uygun olmayan türlerle işlem yapıldığını; KeyError ise sözlükte bulunmayan bir anahtara erişildiğini işaret eder.

Ardından exception satırının hemen üstündeki File bilgisini inceleyin. Dosya adı ve satır numarası, Python yorumlayıcısının hatayı bildirirken hangi konumu işaretlediğini gösterir. Satırın altında çoğu zaman ilgili kaynak kodu da yer alır. Ancak bu satırı doğrudan “kök neden” kabul etmek yerine şu iki soruyu ayrı ayrı sorun: Hata nerede fırlatıldı ve bu noktaya yanlış veri ya da yanlış varsayım nereden geldi?

Python öğrenme pratiğini düzenli sürdürmek isteyenler, hata mesajlarını yalnızca okuyup geçmek yerine her hatayı küçük bir inceleme çalışmasına dönüştürmelidir. Bu yaklaşım, birebir Python dersleri kapsamında kullanılan düşünerek öğrenme pratiğiyle de uyumludur: önce mesajı sınıflandırmak, sonra kanıt toplamak ve en son düzeltme yapmak.

Traceback İçindeki Dosya, Satır, Fonksiyon ve Exception Bilgilerini Ayırma

Traceback İçindeki Dosya, Satır, Fonksiyon ve Exception Bilgilerini Ayırma

Traceback bloğunu tek parça bir hata mesajı gibi okumak yerine görsel olarak bölümlere ayırmak daha kolaydır. Aşağıdaki örnekte main fonksiyonu, load_user fonksiyonunu çağırıyor; hata ise sözlükte olmayan bir anahtara erişildiğinde ortaya çıkıyor:

Traceback (most recent call last):
  File "app.py", line 8, in <module>
    print(load_user(user_data))
  File "app.py", line 5, in load_user
    return data["email"]
KeyError: 'email'

Bu örneği aşağıdaki parçalarla okuyabilirsiniz:

  • Dosya adı: app.py, hatanın veya çağrının hangi dosyada gerçekleştiğini gösterir.
  • Satır numarası: line 5, ilgili dosyada incelemeye başlanacak konumu belirtir.
  • Fonksiyon veya çalışma bağlamı: load_user, hatanın hangi fonksiyon çalışırken ortaya çıktığını gösterir. <module> ise kodun dosyanın üst seviyesinde çalıştığını ifade eder.
  • Kaynak kod satırı: return data["email"], Python’un hatayı bildirirken işaret ettiği işlemi gösterir.
  • Exception türü ve mesajı: KeyError: 'email', data içinde email anahtarının bulunamadığını anlatır.

Traceback’in üst tarafında genellikle çağrının başladığı veya bir önceki aşaması, alt tarafında ise daha güncel çağrı ve hatanın bildirildiği nokta yer alır. Bu örnekte akış şu şekildedir:

<module> → load_user(data) → data["email"] → KeyError

Yani program dosyanın üst seviyesinden load_user fonksiyonuna geçmiş, fonksiyon da kendisine verilen data değeri üzerinden email anahtarını okumaya çalışmıştır. Hatanın fırlatıldığı satır fonksiyon içindedir; fakat yanlış varsayım, fonksiyona gönderilen sözlüğün gerçekten email anahtarını içerdiğinin düşünülmesi olabilir.

Bu ayrım özellikle fonksiyonlar iç içe geçtiğinde önem kazanır. Örneğin bir fonksiyonun içinde total / count işlemi başarısız olabilir. Traceback işlemin yapıldığı satırı gösterir; fakat count değerinin sıfır gelmesine başka bir fonksiyonun sebep olup olmadığı çağrı zinciri incelenmeden anlaşılamaz. Bu nedenle “Python hata mesajı hangi satırı gösteriyor?” sorusu ile “yanlış değer hangi aşamada üretildi?” sorusu aynı değildir.

Kısa bir traceback incelemesinde şu kontrol listesini kullanabilirsiniz:

  • Exception türü nedir?
  • Hangi dosya ve satır numarası işaretlenmiş?
  • İşaretlenen satır hangi fonksiyonun içinde çalışıyor?
  • Bu fonksiyon hangi başka fonksiyon tarafından çağrılmış?
  • İlgili değişkenlerin gerçek değerleri ve türleri nedir?

Beş Adımlı Traceback Teşhis Yöntemi

Aşağıdaki yöntem, traceback’i rastgele satırları değiştirerek değil, kanıt toplayarak incelemenizi sağlar. Her adımın amacı farklıdır; bir sonraki adıma ancak mevcut adımın sorusuna yeterli cevap verdikten sonra geçin.

  1. Exception türünü oku. En alttaki satırda yer alan exception adını belirleyin. NameError, TypeError, KeyError veya başka bir sınıf, hangi problem ailesini araştırmanız gerektiği konusunda ilk ipucunu verir. Ancak exception türünü gördüğünüz anda çözümü kesinleştirmeyin. Örneğin TypeError yalnızca “türlerle ilgili bir uyumsuzluk var” der; hangi değişkenin yanlış olduğunu henüz kanıtlamazsınız.

  2. En alt satırı bul. Exception satırının hemen üstündeki File kaydını ve kaynak kodunu bulun. Bu satır çoğunlukla hatanın bildirildiği işlemdir. Satır numarasını dosyada açın ve gerçekten hangi ifadenin çalıştığını kontrol edin. Burada amaç, traceback’in işaret ettiği noktayı netleştirmektir; henüz kök neden kararı vermek değildir.

  3. Çağrı zincirini yukarı doğru takip et. Traceback’teki File bloklarını alttan üste doğru okuyarak mevcut fonksiyona hangi çağrının geldiğini izleyin. “Bu fonksiyon neden bu değerle çağrıldı?” sorusu, çoğu zaman yalnızca hatalı satıra bakmaktan daha açıklayıcıdır. Bir üst fonksiyonun adı, yanlış verinin program içinde nereden taşındığına dair güçlü bir ipucu verebilir.

  4. İlgili satırdaki değişken değerlerini kontrol et. Şüpheli değişkenin yalnızca adını değil, gerçek değerini ve türünü inceleyin. Geçici olarak print() kullanabilir, daha anlaşılır gösterim için repr() çağırabilir veya koşul kontrolleri ekleyebilirsiniz. Gerekirse işlemi küçük ve yalıtılmış bir testte deneyin. Örneğin bir sözlük anahtarına erişmeden önce "email" in data kontrolü, varsayımınızı görünür hâle getirir.

  5. Hipotezi test et. “Sorun bu değişken boş geliyor” gibi tek bir hipotez kurun ve yalnızca o varsayımı sınayacak küçük bir değişiklik yapın. Sonucu gözlemlemeden aynı anda beş farklı satırı değiştirmeyin. Test hipotezinizi doğrulamıyorsa çözümü zorla korumak yerine yeni kanıta göre hipotezi değiştirin. Böylece hangi değişikliğin sorunu etkilediğini kaybetmezsiniz.

Her traceback için aşağıdaki şablonu doldurmak, teşhisi dağınık bir tahmin olmaktan çıkarıp takip edilebilir bir sürece dönüştürür:

exception türü | işaretlenen dosya ve satır | çağıran fonksiyon | şüpheli değer | test sonucu

Örneğin: KeyError | app.py:5 | main → load_user | data içinde "email" anahtarı yok | anahtar kontrolü başarısız. Bu kayıt, yalnızca neyin bozulduğunu değil, hangi varsayımın test edildiğini de gösterir. Böylece düzeltme yaptıktan sonra traceback’in değişip değişmediğini daha bilinçli değerlendirebilirsiniz.

Fonksiyon Çağrı Zinciri İçeren Hatalı Örnek Üzerinden Teşhis

Bir traceback’i doğru okumak için yalnızca son satırdaki KeyError ifadesine bakmak yeterli değildir. Önce exception türünü ve mesajını okuyun, ardından en alttaki kaynak satırını bulun. Daha sonra çağrı zincirini alttan üste doğru takip ederek hatalı satıra hangi fonksiyonların veri taşıdığını inceleyin. Python traceback’i, hatanın oluştuğu bağlamı dosya, satır ve çağrı sırasıyla gösterir. ([docs.python.org](https://docs.python.org/3/tutorial/errors.html?utm_source=openai))

Aşağıdaki örnekte main(), load_user() fonksiyonunu; load_user() ise get_display_name() fonksiyonunu çağırır. Sözlükte display_name anahtarı bulunmadığı için bilerek KeyError oluşturulur.

def get_display_name(user):
    return user["display_name"]

def load_user():
    user = {"id": 42, "name": "Ada"}
    return get_display_name(user)

def main():
    display_name = load_user()
    print(display_name)

if __name__ == "__main__":
    main()

Dosyanın traceback_ornegi.py adıyla kaydedilip çalıştırıldığını varsayarsak temel traceback aşağıdaki gibi görünür:

Traceback (most recent call last):
  File "traceback_ornegi.py", line 13, in <module>
    main()
  File "traceback_ornegi.py", line 9, in main
    display_name = load_user()
  File "traceback_ornegi.py", line 6, in load_user
    return get_display_name(user)
  File "traceback_ornegi.py", line 2, in get_display_name
    return user["display_name"]
KeyError: 'display_name'

Traceback satırlarının görünümü, çalıştırılan Python ortamına ve editöre göre küçük biçimsel farklılıklar gösterebilir; ancak dosya, satır, çağrı zinciri ve exception bilgilerini birlikte okuma mantığı değişmez. Bu örneği beş adımda inceleyelim.

  1. Exception türünü okuyun. Son satırdaki KeyError: 'display_name', bir sözlükte istenen anahtarın bulunamadığını gösterir. Buradaki hata, fonksiyon çağrısının kendisinden değil, sözlük erişiminden kaynaklanır.
  2. En alt kaynak satırını bulun. Traceback’in en altındaki dosya kaydı, hatanın fırlatıldığı satırı gösterir: return user["display_name"]. Bu satır bir anahtarı sözlükten okumaya çalışmaktadır.
  3. Çağrı zincirini yukarı doğru takip edin. Hata get_display_name() içinde oluşmuştur. Bu fonksiyon load_user() tarafından çağrılmış, load_user() da main() içinden çalıştırılmıştır. Zincir şu şekildedir: get_display_name() → load_user() → main().
  4. Mevcut ve istenen anahtarları karşılaştırın. load_user() içinde oluşturulan sözlükte id ve name anahtarları vardır. Buna karşılık get_display_name(), display_name anahtarını istemektedir. Exception’ın fırlatma noktası ikinci fonksiyondaki sözlük erişimi olsa da kök neden, veri hazırlanırken kullanılan anahtar adı ile veriyi tüketen fonksiyondaki anahtar adının uyuşmamasıdır.
  5. Küçük bir kontrolle hipotezinizi sınayın. Hatanın gerçekten anahtar uyuşmazlığından kaynaklandığını görmek için geçici olarak print(user.keys()) veya print("display_name" in user) yazabilirsiniz. Beklenen sonuç, mevcut anahtarların id ve name olması ve ikinci kontrolün False döndürmesidir.

Bu ayrım önemlidir: traceback size çoğu zaman hata fırlatma noktasını doğrudan gösterir; fakat kök neden daha yukarıda, verinin hazırlanması veya isimlendirilmesi sırasında bulunabilir. Sorunu yalnızca user["display_name"] satırında aramak yerine, bu sözlüğün nerede ve hangi alan adlarıyla oluşturulduğunu da incelemek gerekir.

Hatanın iş kuralına göre iki güvenli çözümü vardır. Eğer görüntülenecek ad bulunamadığında varsayılan bir metin kabul edilebiliyorsa get() kullanılabilir:

def get_display_name(user):
    return user.get("display_name", "İsimsiz kullanıcı")

def load_user():
    user = {"id": 42, "name": "Ada"}
    return get_display_name(user)

def main():
    print(load_user())

if __name__ == "__main__":
    main()

Bu sürümün beklenen çıktısı İsimsiz kullanıcı olur. Ancak uygulama için display_name zorunlu bir alan ise varsayılan değer kullanmak yerine açık bir koşul yazıp daha anlaşılır bir hata mesajı üretmek daha doğru olabilir. Önemli olan, try/except ile hatayı sessizce gizlemek değil, eksik anahtarın uygulama açısından nasıl ele alınacağına bilinçli karar vermektir.

SyntaxError, NameError, TypeError ve KeyError Traceback’te Nasıl Ayırt Edilir?

SyntaxError, NameError, TypeError ve KeyError Traceback’te Nasıl Ayırt Edilir?

Bu exception türlerini ayırt ederken ilk adım aynıdır: mesajın son satırını okuyun, kaynak satırını bulun, çağrı zincirini takip edin ve hataya neden olan değeri veya ifadeyi kontrol edin. Fark, her exception’ın farklı bir soruya cevap vermesidir. SyntaxError çoğunlukla kod çalıştırılmadan önce sözdizimi aşamasında görülür; diğer üç hata ise genellikle çalışan bir ifadenin yürütülmesi sırasında ortaya çıkar. ([docs.python.org](https://docs.python.org/3/tutorial/errors.html?utm_source=openai))

Exception türü Genellikle neyi anlatır? Traceback’te özellikle neye bakılır? İlk teşhis sorusu
SyntaxError Kodun Python sözdizimi kurallarına uymadığını anlatır. Dosya ve satır numarasıyla birlikte gösterilen satırın ve işaretçinin çevresi incelenir. İşaretlenen yer, düzeltilmesi gereken gerçek noktanın hemen öncesi veya sonrası olabilir. Eksik iki nokta, parantez, tırnak veya yanlış girinti var mı?
NameError Kullanılan bir isim tanımlı değildir veya mevcut kapsamda erişilebilir değildir. Kullanılan değişken, fonksiyon ya da sınıf adı; tanımlandığı yer ve kapsamla karşılaştırılır. İsim doğru yazılmış mı ve bu noktada gerçekten tanımlı mı?
TypeError Bir işlem, aldığı değer türleriyle uyumlu değildir. Hata mesajında beklenen ve alınan türlere, ayrıca işlemin yapıldığı satıra bakılır. Bu işlem için kullanılan değerlerin türleri ve işlem sırası doğru mu?
KeyError Sözlükte bulunmayan bir anahtar istenmiştir. İstenen anahtar adı ile ilgili sözlüğün mevcut anahtarları karşılaştırılır. Bu anahtar veri içinde gerçekten var mı, yoksa adı başka mı?

Örneğin NameError gördüğünüzde doğrudan “değişkeni tanımla” demek yerine, traceback’teki satırı ve çağıran fonksiyonun hangi kapsamda çalıştığını kontrol edin. TypeError için yalnızca tür adını değil, hatalı işleme giren gerçek değerleri inceleyin. KeyError için ise sözlüğün oluşturulduğu noktaya kadar geri gidin. Böylece her hata türüne tek satırlık sihirli çözüm aramak yerine aynı teşhis yöntemini farklı veri ve kapsam sorularına uygulamış olursunuz.

Sadece Son Satırı Aratmak Neden Yetmez?

KeyError veya TypeError ifadesini tek başına arama motoruna yazmak genellikle genel tanımlar getirir; sizin programınızdaki hatanın nedenini açıklamayabilir. Aynı exception türü, farklı veri hazırlama hatalarından, yanlış fonksiyon çağrısından veya beklenmeyen kullanıcı girdisinden kaynaklanabilir. Daha yararlı bir araştırma için exception türünü, ilgili kod satırını, beklenen veri biçimini ve çağrı bağlamını birlikte değerlendirin.

  • Dosya ve satır bilgisini silmeyin. Hangi satırda ve hangi fonksiyon içinde hata oluştuğu teşhisin temelidir.
  • Traceback’in ilk satırını otomatik olarak kök neden sanmayın. İlk kayıt çoğu zaman programın çağrıyı başlattığı yeri, en alt kayıt ise exception’ın fırlatıldığı noktayı gösterir.
  • Çağıran fonksiyonun gönderdiği veriyi kontrol edin. Hatalı değer, exception’ın görüldüğü fonksiyondan önce hazırlanmış olabilir.
  • Hatanın anlamını kavramadan rastgele try/except eklemeyin. Bu yaklaşım problemi çözmek yerine gerçek nedeni görünmez hâle getirebilir.

Traceback paylaşırken kişisel verileri, erişim belirteçlerini, parolaları, API anahtarlarını ve dosya yollarındaki özel bilgileri maskeleyin. Hata mesajını kısaltırken çağrı zincirini ve satır numaralarını koruyun; aksi hâlde teşhis için en değerli bağlam kaybolur. Python bilginizde hangi konuları tekrar etmeniz gerektiğini görmek için Python bilgi testi üzerinden mevcut seviyenizi ölçebilirsiniz.

Traceback paylaşmadan önce kontrol listesi:

  • Tüm çağrı zincirini korudum mu?
  • Dosya ve satır bilgilerini sildim mi?
  • Hassas bilgileri maskeledim mi?
  • Hatayı üreten en küçük örneği ayırabildim mi?
  • Denediğim hipotezi ve beklediğim sonucu yazdım mı?

Traceback Okuma Pratiği İçin Uygulanabilir Kontrol Listesi

Bir traceback ile karşılaştığınızda aynı karar akışını izlemek, rastgele kod değiştirmek yerine kanıta dayalı ilerlemenizi sağlar. Hata yapmak öğrenme sürecinin doğal bir parçasıdır; önemli olan, her hatayı incelenebilir bir probleme dönüştürmektir.

  1. Exception türünü ve mesajını yazın. Örneğin KeyError: 'email' ifadesi, kodun bulunmayan bir anahtara erişmeye çalıştığını gösterir.
  2. En alttaki ilgili dosya ve satır bilgisini işaretleyin. Bu satır hatanın görünür hâle geldiği noktadır; ancak hatanın temel nedeni daha önce hazırlanmış yanlış bir değer olabilir.
  3. Çağrı zincirini aşağıdan yukarıya okuyun. Hatalı satıra hangi fonksiyonların ve çağrıların ulaştığını belirleyin.
  4. Şüpheli değerleri gözlemleyin. İlgili argümanların türünü, sözlük anahtarlarını, değişken adlarını ve beklenmeyen None değerlerini kontrol edin.
  5. Tek bir hipotez kurun. “Sözlükte email anahtarı bulunmuyor” gibi sınanabilir bir açıklama seçin.
  6. Küçük bir test çalıştırın. İlgili değeri yazdırın, yalnızca sorunlu fonksiyonu çağırın veya minimum veriyle hatayı yeniden üretin.
  7. Sonucu kaydedin. Hipotez doğrulanmadıysa yeni bulguya göre bir sonraki hipoteze geçin.

Örneğin bir KeyError senaryosunda şüpheli sözlüğün anahtarları incelenir. Aynı yöntem NameError için değişkenin tanımlandığı kapsamı, TypeError için değerlerin türlerini, SyntaxError içinse işaretlenen satırı ve hemen öncesindeki söz dizimini kontrol etmeye uyarlanabilir. Genel kodlama seviyenizi ayrıca görmek isterseniz ücretsiz yazılım bilgisi değerlendirmesini kullanabilirsiniz.

Boş Teşhis Notu Şablonu

Exception türü ve mesajı:
Dosya, satır ve fonksiyon:
Çağrı zinciri:
Şüpheli değişken veya argüman:
Beklenen değer:
Gözlenen değer:
Hipotezim:
Uyguladığım küçük test:
Test sonucu:
Yaptığım düzeltme:

Sık Sorulan Sorular

Traceback’in en alt satırı her zaman gerçek hata kaynağını mı gösterir?

Hayır. En alt satır genellikle exception türünü ve hatanın görünür olduğu noktayı gösterir. Asıl neden, daha önce oluşturulan yanlış bir değer veya üst çağrılardan gelen hatalı bir argüman olabilir.

“Traceback (most recent call last)” ifadesi ne anlama gelir?

Hata oluşmadan önce izlenen fonksiyon çağrılarının gösterileceğini belirtir. Kayıtlar çağrı zincirini ortaya koyar; teşhis sırasında en alttaki ilgili kod satırından başlayıp yukarı doğru ilerlemek pratiktir.

Python traceback içinde dosya adı ve satır numarası nasıl bulunur?

File ile başlayan kayıtlarda dosya yolu, line ifadesinden sonra satır numarası ve varsa in bölümünden sonra fonksiyon adı görülür.

Bir hata mesajını arama motorunda ararken traceback’in tamamını paylaşmak gerekir mi?

Genellikle önce exception türünü, genel hata mesajını ve ilgili teknoloji adını aramak yeterlidir. Dosya yolları, kullanıcı bilgileri, erişim anahtarları ve özel veriler temizlenmeden traceback’in tamamı paylaşılmamalıdır.

Traceback okurken değişken değerlerini nasıl kontrol edebilirim?

Geçici print() çağrıları, type(), repr() veya bir hata ayıklayıcının adım adım inceleme özellikleri kullanılabilir. Amaç, değişkenin beklenen değer ve türle eşleşip eşleşmediğini görmektir.

Traceback okuma becerisi tekrarlarla gelişir. Her hatada aynı kontrol listesini uygulamak, hata mesajlarını zamanla korkutucu çıktılar olmaktan çıkarıp sistemli teşhis ipuçlarına dönüştürür.

Bu içerik aradığın cevabı verdi mi?
Yanıtın, hangi yazıları geliştirmemiz gerektiğini anlamamıza yardımcı olur.
Bu içeriğin üretilmesinde yapay zeka araçlarından destek alınmıştır.

Bu konudan sonra ne okuyabilirsin?

Tüm yazılar

İlgili Eğitimler

Berk Keskin — Yazılım Geliştirici ve Eğitmen
Yazar

Berk Keskin Kimdir?

Yazılıma 12 yaşında başladı; bugün öğrencinin seviyesine ve hedefine göre şekillenen sürdürülebilir öğrenme sistemleri tasarlıyor. 500'den fazla kişiye ezber değil, düşünerek kod yazmayı öğretti — Berk Akademi'de izlemeye değil üretmeye dayalı öğrenme kültürünü o kuruyor.

WhatsApp Hemen Ara