feder-cr/Jobs_Applier_AI_Agent_AIHawk · error · AttributeError
AttributeError in Education: {e}
Error message
AttributeError in Education: {e} What it means
An AttributeError escaped while processing one education entry — usually because `edu` is not a dict (e.g. a string or None from malformed JSON) so edu.get(...) fails, or a nested value expected to be an object is a scalar. The chained original exception names the attribute.
Source
Thrown at src/resume_schemas/resume.py:155
for edu in data:
try:
exams = [Exam(name=k, grade=v) for k, v in edu.get('exam', {}).items()]
education = EducationDetails(
education_level=edu.get('education_level'),
institution=edu.get('institution'),
field_of_study=edu.get('field_of_study'),
final_evaluation_grade=edu.get('final_evaluation_grade'),
start_date=edu.get('start_date'),
year_of_completion=edu.get('year_of_completion'),
exam=exams
)
education_list.append(education)
except KeyError as e:
raise KeyError(f"Missing field in education details: {e}") from e
except TypeError as e:
raise TypeError(f"Invalid data for Education: {e}") from e
except AttributeError as e:
raise AttributeError(f"AttributeError in Education: {e}") from e
except Exception as e:
raise Exception(f"Unexpected error in Education processing: {e}") from e
return education_list
def _process_experience_details(self, data: List[Dict[str, Any]]) -> List[ExperienceDetails]:
experience_list = []
for exp in data:
try:
key_responsibilities = [
Responsibility(description=list(resp.values())[0])
for resp in exp.get('key_responsibilities', [])
]
skills_acquired = [str(skill) for skill in exp.get('skills_acquired', [])]
experience = ExperienceDetails(
position=exp['position'],
company=exp['company'],
employment_period=exp['employment_period'],
location=exp['location'],View on GitHub (pinned to 79155b52fa)
Solutions
- Read e.__cause__ to identify the offending object type.
- Filter/normalize the list first: entries = [e for e in data if isinstance(e, dict)].
- Wrap per-entry handling so one bad entry doesn't abort the whole resume (skip-and-log instead of raise).
Example fix
// before
for edu in data:
exams = [Exam(name=k, grade=v) for k, v in edu.get('exam', {}).items()]
# after
for edu in data:
if not isinstance(edu, dict):
logger.warning('skipping non-dict education entry: %r', edu)
continue
... Defensive patterns
Strategy: type-guard
Validate before calling
data = [e for e in data if isinstance(e, dict)] # optionally log dropped entries
Type guard
def all_dicts(seq: Any) -> TypeGuard[list[dict]]:
return isinstance(seq, list) and all(isinstance(e, dict) for e in seq) Try / catch
try:
edu_list = _process_education_details(data)
except AttributeError as e:
logger.warning("malformed education entry (%s); skipping", e)
edu_list = [ ] # or partial results Prevention
- Filter non-dict entries out of extracted lists before processing
- Skip-and-log instead of failing the whole resume
- Check nested value types before attribute access
When it happens
Trigger: data containing education entries that are strings/None: for edu in ['BSc Computer Science', None] → 'str' object has no attribute 'get'.
Common situations: Heterogeneous extraction output where some entries are plain text instead of structured dicts; null entries in sparse resumes.
Related errors
- AttributeError in PersonalInformation: {e}
- AttributeError in Experience: {e}
- Error in self_identification data: {e}
- Attribute error in self_identification processing.
- Attribute error in legal_authorization processing.
AI-assisted analysis of feder-cr/Jobs_Applier_AI_Agent_AIHawk@79155b52fa (2026-08-28).
Data as JSON: /api/errors/705cb2cddcc26d02.
Report an issue: GitHub.