«script» doesn’t understand the “handlerName” message

I wrestled with this all day yesterday and still can’t see anything wrong with this statement. Can someone give me a clue, please?

I’m getting this error message:

«script» doesn’t understand the “intYearsSince” message.

On this statement within a Tell block:

set intAge to my intYearsSince(dateBirthday)

Script Debugger says that dateBirthday is

date "Wednesday, June 3, 1942 at 12:00:00 PM"

The handler is NOT even entered, but here it is for completeness:

on intYearsSince(theDate)
	(*
		Dates specified with just a month and day use the year 1604.
	
	*)
	log "Entered intYearsSince"
	set intYear to year of theDate as integer
	log "theDate = " & theDate
	log "intYear = " & intYear
	log "gIntTodayYear = " & gIntTodayYear
	if intYear is less than 1605 then
		set intReturnValue to 0
	else
		set intReturnValue to gIntTodayYear - intYear
	end if
	log "Entered intYearsSince"
	return intReturnValue as integer
end intYearsSince

This compiles and run for me, but inside your hanlder no value was set for the local variable gIntTodayYear so I set it in the first line.

set dateBirthday to date "Wednesday, June 3, 1942 at 12:00:00 PM"
set intAge to my intYearsSince(dateBirthday)

on intYearsSince(theDate)
   set gIntTodayYear to 1605
   (*
      Dates specified with just a month and day use the year 1604.
   
   *)
   log "Entered intYearsSince"
   set intYear to year of theDate as integer
   log "theDate = " & theDate
   log "intYear = " & intYear
   log "gIntTodayYear = " & gIntTodayYear
   if intYear is less than 1605 then
      set intReturnValue to 0
   else
      set intReturnValue to gIntTodayYear - intYear
   end if
   log "Entered intYearsSince"
   return intReturnValue as integer
end intYearsSince

Yes, gIntTodayYear is a global variable and is set outside of the handler. Sorry, I should have mentioned this.

Yes, alone it runs just fine. It also runs fine from within a Tell block as demonstrated in this stub code:

-- Declare required resouces
use AppleScript version "2.4" -- Yosemite (10.10) or later
use scripting additions


global gIntTodayYear

on run
	--
	-- Configuration
	set dateToday to current date
	log "dateToday = " & dateToday
	set gIntTodayYear to (year of (dateToday))
	log "gIntTodayYear = " & gIntTodayYear
	--
	--
	tell application "Contacts"
		--
		-- Default time out is 2 minutes which may not be long enough for a large number of greetings.
		set blnIsDead to false
		set dateWedding to date "Friday, June 2, 2000 at 12:00:00 AM"
		set blnSendAnniversaryGreeting to true
		if not blnIsDead then
			set blnHasAppropriateEmail to true
			if blnHasAppropriateEmail then
				set dateBirthday to date "Saturday, June 2, 1900 at 12:00:00 AM"
				set blnSendBirthdayGreeting to true
				if blnSendBirthdayGreeting or blnSendAnniversaryGreeting then
					if blnSendBirthdayGreeting then
						try
							set intYearsOld to my intYearsSince(dateBirthday)
						on error
							log "birthday error"
						end try
					end if
					if blnSendAnniversaryGreeting then
						try
							set intYearsSinceWedding to my intYearsSince(dateWedding)
						on error
							log "anniversary error"
						end try
						
					end if
				end if
			end if
		end if
	end tell
end run


on intYearsSince(theDate)
	(*
		Dates specified with just a month and day use the year 1604.
	*)
	log "Entered intYearsSince"
	set intYear to year of theDate as integer
	log "theDate = " & theDate
	log "intYear = " & intYear
	log "gIntTodayYear = " & gIntTodayYear
	if intYear is less than 1605 then
		set intReturnValue to 0
	else
		set intReturnValue to gIntTodayYear - intYear
	end if
	log "Exit intYearsSince"
	return intReturnValue as integer
end intYearsSince

The stub script above is a stripped down version of the more complex script I’m having a problem with, which is shown at the end of this post.

This more-complex script compiles just fine but it generates this runtime error:

From what I’ve read, this Execution Error often is the result of referring to a handler within a tell block and failing to preface the handler’s name with the keyword my; failure to use my implies that the handler’s name is a reference to an object in the tell block’s application, which does not exist so a runtime error results.

The bottom line is that for some reason, the tell block in my complex script below doesn’t see the handler and so it’s looking for an application object named intYearsSince instead.

Is there a way to use Script Debugger to show an object model of the script at runtime?

Anyway, I can’t figure out why the script is mistaking intYearsSince for an object instead of a handler.

What is it about my complex script that prevents seeing that intYearsSince is a handler?

Sorry this script demonstrating the problem is so long. So far, my efforts at removing code incrementally to figure out what trips the problem have not been fruitful.

Thank you for your help.

--
-- Declare global variables
global gStrBodyMessage, gStrBlankLine, gStrNewline, gIntTodayYear
--
-- Declare required resouces
use AppleScript version "2.4" -- Yosemite (10.10) or later
use scripting additions

on intYearsSince(theDate)
	(*
		Dates specified with just a month and day use the year 1604.
	*)
	log "Entered intYearsSince"
	set intYear to year of theDate as integer
	log "theDate = " & theDate
	log "intYear = " & intYear
	log "gIntTodayYear = " & gIntTodayYear
	if intYear is less than 1605 then
		set intReturnValue to 0
	else
		set intReturnValue to gIntTodayYear - intYear
	end if
	log "Exit intYearsSince"
	return intReturnValue as integer
end intYearsSince


on run
	--
	-- Configuration
	set strSmartGroupForPeopleHavingBirthdayOrAnniversaryToday to "Greeting"
	set strContactDateLabelAnniversary to "Anniversary"
	set strContactEmailLabelHome to "home"
	set strContactEmailLabelWork to "work"
	set strContactEmailLabelSchool to "school"
	set strContactDateLabelDeath to "death"
	set gStrBodyMessage to "I hope that you have a special celebration planned for today."
	set gStrBodySignature to "- nello"
	set strOccasionBirthday to "Birthday"
	set strOccasionAnniversary to "Anniversary"
	set strOccasionBirthdayEmoji to "🎈"
	set strOccasionAnniversaryEmoji to "🎂"
	set intTimeoutSeconds to 500
	set blnDebug to false
	--
	-- Constants
	set intTimeoutSeconds to 500
	set dateToday to (current date)
	set strTodayMonthDay to strMonthDay(dateToday)
	set gIntTodayYear to (year of (dateToday)) as integer
	set strBodyMessage to "I hope that you have a special celebration planned for today."
	set strLF to ASCII character 10
	set strCR to ASCII character 13
	set gStrNewline to strCR & strLF
	set gStrBlankLine to gStrNewline & gStrNewline
	--
	--  variables
	set blnIsDead to missing value
	set dateWedding to missing value
	set strDateLabel to missing value
	set blnSendAnniversaryGreeting to missing value
	set blnHasAppropriateEmail to missing value
	set strEmailName to missing value
	set blnSendBirthdayGreeting to missing value
	set blnSendAnniversaryGreeting to missing value
	set dateBirthday to missing value
	set strEmailAddress to missing value
	set intYearsSince to missing value
	
	-- 
	-- Begin test stub
	set dateTest to date "Friday, June 3, 2022 at 12:00:00 AM"
	set strTodayMonthDay to my strMonthDay(dateTest)
	set gIntTodayYear to (year of (dateTest)) as integer
	set blnDebug to true
	-- End test stub
	--
	
	
	tell application "Contacts"
		--
		-- Default time out is 2 minutes which may not be long enough for a large number of greetings.
		with timeout of intTimeoutSeconds seconds
			-- 
			-- Get list of people with birthdays or anniversaries recorded in Contacts
			set peopleToCheck to people of group strSmartGroupForPeopleHavingBirthdayOrAnniversaryToday
			repeat with thePerson in peopleToCheck
				if blnDebug then
					log "Name = " & name of thePerson
				end if
				-- Initialize variables for each person.
				set blnIsDead to false
				set dateWedding to missing value
				set blnSendAnniversaryGreeting to false
				set blnSendBirthdayGreeting to false
				set blnHasAppropriateEmail to false
				--
				-- Check custom dates to: (1) see whether person is dead, and (2) get anniversary data
				repeat with theDate in custom dates of thePerson
					set strDateLabel to label of theDate
					ignoring case
						if strDateLabel contains strContactDateLabelDeath then
							--
							-- Assume that person is dead regardless of value of date
							set blnIsDead to true
						else if strDateLabel contains strContactDateLabelAnniversary then
							set dateWedding to value of theDate
							if dateWedding is not missing value then
								set blnSendAnniversaryGreeting to my strMonthDay(dateWedding) is equal to strTodayMonthDay
							end if
						end if
					end ignoring
				end repeat
				if not blnIsDead then
					--
					-- Check whether person's birthday is today
					set dateBirthday to birth date of thePerson
					if dateBirthday is missing value then
						set blnSendBirthdayGreeting to false
					else
						set blnSendBirthdayGreeting to my strMonthDay(dateBirthday) is equal to strTodayMonthDay
					end if
					-- 
					-- Check whether any greeting should be drafted.			
					if blnSendBirthdayGreeting or blnSendAnniversaryGreeting then
						--
						-- Check whether person has an appropriate email address
						set strEmailHome to missing value
						set strEmailWork to missing value
						set strEmailSchool to missing value
						ignoring case
							repeat with theEmail in every email of thePerson
								set strEmailLabel to label of theEmail
								--
								-- Check for a home email.
								if strEmailLabel contains strContactEmailLabelHome then
									set strEmailHome to value of theEmail
									-- 
									-- Found first home email address so quit looking at others
									exit repeat
								else if strEmailWork is equal to missing value then
									--
									-- Work email not found yet so check this one.
									if strEmailLabel contains strContactEmailLabelWork then
										set strEmailWork to value of theEmail
									end if
								else if strEmailSchool is equal to missing value then
									--
									-- School email not found yet so check this one.
									if strEmailLabel contains strContactEmailLabelSchool then
										set strEmailSchool to value of theEmail
									end if
								end if
							end repeat
						end ignoring
						set blnHasAppropriateEmail to true
						if strEmailHome is not equal to missing value then
							set strEmailAddress to strEmailHome
						else if strEmailWork is not equal to missing value then
							set strEmailAddress to strEmailWork
						else if strEmailSchool is not equal to missing value then
							set strEmailAddress to strEmailSchool
						else
							set blnHasAppropriateEmail to false
						end if
						if blnDebug then
							log "blnHasAppropriateEmail = " & blnHasAppropriateEmail
						end if
						if blnHasAppropriateEmail then
							--
							-- Extract preferred name for this person.
							if nickname of thePerson is not missing value then
								set strEmailName to nickname of thePerson
							else
								set strEmailName to first name of thePerson & last name of thePerson
							end if
							--
							-- Draft birthday greeting, if any.
							if blnSendBirthdayGreeting then
								set intAge to my intYearsSince(dateBirthday)
								my draftEmail(strEmailName, strEmailAddress, intAge, strOccasionBirthday, strOccasionBirthdayEmoji)
							end if
							--
							-- Draft anniversary greeting, if any.
							if blnSendAnniversaryGreeting then
								try
									set intYearsSinceWedding to my intYearsSince(dateWedding)
								on error errMsg number errNum
									log "errMsg = " & errMsg
									log "errNum = " & errNum
									-- your error handler code goes here
								end try
								my draftEmail(strEmailName, strEmailAddress, intYearsSinceWedding, strOccasionBirthday, strOccasionAnniversaryEmoji)
							end if
						end if
					end if
				end if
			end repeat
		end timeout
	end tell
end run

on strMonthDay(theDate)
	(* 
	Return theDate's month name and day number as string. (Ignores year and time.) 
*)
	set strReturnValue to (month of theDate as text) & " " & (day of theDate) as text
	return strReturnValue
end strMonthDay


on draftEmail(theName, theEmail, theSubjectYears, theSubjectOccasion, theEmoji)
	(*
Create draft email in default mailer.
*)
	set theSubject to "Happy "
	--
	-- A year is NOT required in birth date and anniversary date. 
	-- A zero indicates that the year is not know and thus 
	-- the number of years since the occasion is NOT known.
	if theSubjectYears is greater than 0 then
		--
		-- Include the number of years in the subject.
		set theSubject to theSubject & theSubjectYears & strOrdinalNumber(theSubjectYears)
	end if
	set theSubject to theSubject & " " & theSubjectOccasion & " " & theEmoji
	set theBody to first word of theName & ":" & gStrBlankLine & gStrBodyMessage & gStrBlankLine & gStrBodySignature
	set theURL to "mailto:" & theName & "<" & theEmail & ">?&subject=" & theSubject & "&body=" & theBody
	log theURL
	open location theURL
end draftEmail


on strOrdinalNumber(theCardinalNumber)
	(*
	Append an English ordinal suffix to a number and return the result as string.
	Author: Nigel Garvey
	Source: https://macscripter.net/viewtopic.php?id=20878
*)
	set units to theCardinalNumber mod 10
	if (units > 3) or ((theCardinalNumber - units) mod 100 is 10) or (units < 1) or (units mod 1 > 0) then
		set strOrdinalSuffix to "th"
	else
		set strOrdinalSuffix to item units of {"st", "nd", "rd"}
	end if
	set strReturnValue to (theCardinalNumber as string) & strOrdinalSuffix
	return strReturnValue
end strOrdinalNumber

Your stub script seem to run fine for me on macOS 12.4.

Are you still experiencing issues with the stub script provided above?

My guess is this line is the problem:

set intYearsSince to missing value

You’re using the same name for a handler and variable – don’t do that.

1 Like

Bingo! That fixed it.

Thank you.

This topic was automatically closed 3 days after the last reply. New replies are no longer allowed.