Troubleshooting Your Macros

Solving Common Macro Problems

The following table lists some problems that you might encounter when working with the macro facility. Because many of these problems do not cause error messages to be written to the SAS log, solving them can be difficult. For each problem, the table gives some possible causes and solutions.
Commonly Encountered Macro Problems
Problem
Cause
Explanation
SAS windowing environment session stops responding after you submit a macro definition. You type and submit code but nothing happens.
  • Syntax error in %MEND statement
  • Missing semicolon, parenthesis, or quotation mark
  • Missing %MEND statement
  • Unclosed comment
The %MEND statement is not recognized and all text is becoming part of the macro definition.
SAS windowing environment session stops responding after you call a macro.
An error in invocation, such as forgetting to provide one or more parameters, or forgetting to use parentheses when invoking a macro that is defined with parameters.
The macro facility is waiting for you to finish the invocation.
The macro does not compile when you submit it.
A syntax error exists somewhere in the macro definition.
Only syntactically correct macros are compiled.
The macro does not execute when you call it or partially executes and stops.
  • A bad value was passed to the macro (for example, as a parameter).
  • A syntax error exists somewhere in the macro definition.
A macro successfully executes only when it receives the correct number of parameters that are of the correct type.
The macro executes but the SAS code gives bad results or no results.
Incorrect logic in the macro or SAS code.
Code runs fine if submitted as open code, but when generated by a macro, the code does not work and issues strange error messages.
  • Tokenization is not as you intended.
  • A syntax error exists somewhere in the macro definition.
Rarely, macro quoting functions alter the tokenization of text enclosed in them. Use the %UNQUOTE Function.
A %MACRO statement generates “invalid statement” error.
  • The MACRO system option is turned off.
  • A syntax error exists somewhere in the macro definition.
For the macro facility to work, the MACRO system option must be on. Edit your SAS configuration file accordingly.
The following table lists some common macro error and warning messages. For each message, some probable causes are listed, and pointers to more information are provided.
Common Macro Error Messages and Causes
Error Message
Possible Causes
For More Information
Apparent invocation of macro xxx not resolved.
  • You have misspelled the macro name.
  • MAUTOSOURCE system option is turned off.
  • MAUTOSOURCE is on, but you have specified an incorrect pathname in the SASAUTOS= system option.
  • You are using the autocall facility but have given the macro and file different names.
  • You are using the autocall facility but did not give the file the .sas extension.
  • There is a syntax error within the macro definition.
Apparent symbolic reference xxx not resolved.
  • You are trying to resolve a macro variable in the same DATA step as the CALL SYMPUT that created it.
  • You have misspelled the macro variable name.
  • You are referencing a macro variable that is not in scope.
  • You have omitted the period delimiter when adding text to the end of the macro variable.

Solving Macro Variable Resolution Problems

When the macro processor examines a name token that follows an &, it searches the macro symbol tables for a matching macro variable entry. If it finds a matching entry, it pulls the associated text from the symbol table and replaces &name on the input stack. A macro variable name is passed to the macro processor, but the processor does not find a matching entry in the symbol tables. So, it leaves the token on the input stack and generates this message:
WARNING: Apparent symbolic reference
NAME not resolved.
The unresolved token is transferred to the input stack for use by other parts of SAS.
Note: You receive the WARNING only if the SERROR system option is on.
To solve these problems, check that you have spelled the macro variable name right and that you are referencing it in an appropriate scope.
When a macro variable resolves but does not resolve to the correct value, you can check several things. First, if the variable is a result of a calculation, ensure that the correct values were passed into the calculation. And, ensure that you have not inadvertently changed the value of a global variable. (See Solving Problems with Macro Variable Scope for more details about variable scope problems.)
Another common problem is adding text to the end of a macro variable but forgetting to add a delimiter that shows where the macro variable name ends and the added text begins. For example, suppose you want to write a TITLE statement with a reference to WEEK1, WEEK2, and so on. You set a macro variable equal to the first part of the string and supply the week's number in the TITLE statement:
%let wk=week;

title "This is data for &wk1";   /* INCORRECT */
When these statements compile, the macro processor looks for a macro variable named WK1, not WK. To fix the problem, add a period (the macro delimiter) between the end of the macro variable name and the added text, as in the following statements:
%let wk=week;

title "This is data for &wk.1";
CAUTION:
Do not use AF, DMS, or SYS as prefixes with macro variable names.
The letters AF, DMS, and SYS are frequently used by SAS as prefixes for macro variables created by SAS. SAS does not prevent you from using AF, DMS, or SYS as a prefix for macro variable names. However, using these strings as prefixes might create a conflict between the names that you specify and the name of a SAS created macro variable (including automatic macro variables in later SAS releases). If a name conflict occurs, SAS might not issue a warning or error message, depending on the details of the conflict. Therefore, the best practice is to avoid using the strings AF, DMS, or SYS as the beginning characters of macro names and macro variable names.

Solving Problems with Macro Variable Scope

A common mistake that occurs with macro variables concerns referencing local macro variables outside of their scopes. As described in Scopes of Macro Variables macro variables are either global or local. Referencing a variable outside of its scope prevents the macro processor from resolving the variable reference. For example, consider the following program:
%macro totinv(var);
   data inv;
      retain total 0;
      set sasuser.houses end=final;
      total=total+&var;
      if final then call symput("macvar",put(total,dollar14.2));
   run;
   %put **** TOTAL=&macvar ****;
%mend totinv;

%totinv(price)
%put **** TOTAL=&macvar ****;   /* ERROR */
When you submit these statements, the %PUT statement in the macro TOTINV writes the value of TOTAL to the log. The %PUT statement that follows the macro call generates a warning message and writes the text TOTAL=&macvar to the log, as follows:
TOTAL= $1,240,800.00
WARNING: Apparent symbolic reference MACVAR not resolved.
**** TOTAL=&macvar ****
The second %PUT statement fails because the macro variable MACVAR is local to the TOTINV macro. To correct the error, you must use a %GLOBAL statement to declare the macro variable MACVAR.
Another common mistake that occurs with macro variables concerns overlapping macro variable names. If, within a macro definition, you refer to a macro variable with the same name as a global macro variable, you affect the global variable, which might not be what you intended. Either give your macro variables distinct names or use a %LOCAL statement to specifically define the variables in a local scope. See Forcing a Macro Variable to Be Local for an example of this technique.

Solving Open Code Statement Recursion Problems

Recursion is something calling itself. Open code recursion is when your open code erroneously causes a macro statement to call another macro statement. This call is referred to as a recursive reference. The most common error that causes open code recursion is a missing semicolon. In the following example, the %LET statement is not terminated by a semicolon:
%let a=b   /* ERROR */
%put **** &a ****;
When the macro processor encounters the %PUT statement within the %LET statement, it generates this error message:
ERROR: Open code statement recursion detected.
Open code recursion errors usually occur because the macro processor is not reading your macro statements as you intended. Careful proofreading can usually solve open code recursion errors, because this type of error is mostly the result of typos in your code, not errors in execution logic.
To recover from an open code recursion error, first try submitting a single semicolon. If that does not work, try submitting the following string:
*'; *"; *); */; %mend; run;
Continue submitting this string until the following message appears in the SAS log:
ERROR: No matching %MACRO statement for this %MEND statement.
If the above method does not work, close your SAS session and restart SAS. Of course, closing and restarting SAS causes you to lose any unsaved data. Be sure to save often while you are developing your macros, and proofread them carefully before you submit them.

Solving Problems with Macro Functions

Some common causes of problems with macro functions include the following:
  • misspelling the function name
  • omitting the opening or closing parenthesis
  • omitting an argument or specifying an extra argument
If you encounter an error related to a macro function, you might also see other error messages. The messages are generated by the invalid tokens left on the input stack by the macro processor.
Consider the following example. The user wants to use the %SUBSTR function to assign a portion of the value of the macro variable LINCOLN to the macro variable SECONDWD. But a typo exists in the second %LET statement, where %SUBSTR is misspelled as %SUBSRT:
%macro test;
%let lincoln=Four score and seven;
%let secondwd=%subsrt(&lincoln,6,5);   /* ERROR */
%put *** &secondwd ***;
%mend test;

%test
When the erroneous program is submitted, the following appears in the SAS log:
WARNING: Apparent invocation of macro SUBSRT not resolved.
The error messages clearly point to the function name, which is misspelled.

Solving Unresolved Macro Problems

When a macro name is passed to the macro processor but the processor does not find a matching macro definition, it generates the following message:
WARNING: Apparent invocation of macro
NAME not resolved.
This error could be caused by the following:
  • the misspelling of the name of a macro or a macro function
  • an error in a macro definition that caused the macro to be compiled as a dummy macro
A dummy macro is a macro that the macro processor partially compiles but does not store.
Note: You receive this warning only if the MERROR system option is on.

Solving the “Black Hole” Macro Problem

When the macro processor begins compiling a macro definition, it reads and compiles tokens until it finds a matching %MEND statement. If you omit a %MEND statement or cause it to be unrecognized by omitting a semicolon in the preceding statement, the macro processor does not stop compiling tokens. Every line of code that you submit becomes part of the macro.
Resubmitting the macro definition and adding the %MEND statement does not correct the error. When you submit the corrected definition, the macro processor treats it as a nested definition in the original macro definition. The macro processor must find a matching %MEND statement to stop compilation.
Note: It is a good practice to use the %MEND statement with the macro name, so you can easily match %MACRO and %MEND statements.
If you recognize that SAS is not processing submitted statements and you are not sure how to recover, submit %MEND statements one at a time until the following message appears in the SAS log:
ERROR: No matching %MACRO statement for this %MEND statement.
Then recall the original erroneous macro definition, correct the error in the %MEND statement, and submit the definition for compilation.
There are other syntax errors that can create similar problems, such as unmatched quotation marks and unclosed parentheses. Often, one of these syntax errors leads to others. Consider the following example:
%macro rooms;
   /* other macro statements& */
   %put **** %str(John's office) ****;   /* ERROR */
%mend rooms;

%rooms
When you submit these statements, the macro processor begins to compile the macro definition ROOMS. However, the single quotation mark in the %PUT statement is not marked by a percent sign. Therefore, during compilation the macro processor interprets the single quotation mark as the beginning of a literal token. It does not recognize the closing parenthesis, the semicolon at the end of the statement, or the %MEND statement at the end of the macro definition.
To recover from this error, you must submit the following:
');
%mend;
If the above methods do not work, try submitting the following string:
*'; *"; *); */; %mend; run;
Continue submitting this string until the following message appears in the SAS log:
ERROR: No matching %MACRO statement for this %MEND statement.
Obviously, it is easier to catch these errors before they occur. You can avoid subtle syntax errors by carefully checking your macros before submitting them for compilation. See Developing Bug-free Macros for a syntax checklist.
Note: Another cause of unexplained and unexpected macro behavior is using a reserved word as the name of a macro variable or macro. For example, because SAS reserves names starting with SYS, you should not create macros and macro variables with names beginning with SYS. Most host environments have reserved words too. For example, on PC-based platforms, the word CON is reserved for console input. Check Reserved Words in the Macro Facility for reserved SAS keywords. Check your SAS companion for host environment reserved words.

Resolving Timing Issues

Many macro errors occur because a macro variable resolves at a different time than when the user intended or a macro statement executes at an unexpected time. A prime example of the importance of timing is when you use CALL SYMPUT to write a DATA step variable to a macro variable. You cannot use this macro variable in the same DATA step where it is defined; only in subsequent steps (after the DATA step's RUN statement).
The key to preventing timing errors is to understand how the macro processor works. In simplest terms, the two major steps are compilation and execution. The compilation step resolves all macro code to compiled code. Then the code is executed. Most timing errors occur because of the following:
  • the user expects something to happen during compilation that does not actually occur until execution
  • expects something to happen later but is actually executed right away
Here are two examples to help you understand why the timing of compilation and execution can be important.

Example of a Macro Statement Executing Immediately

In the following program, the user intends to use the %LET statement and the SR_CIT variable to indicate whether a data set contains any data for senior citizens:
data senior;
   set census;
   if age > 65 then
   do;
      %let sr_cit = yes;  /* ERROR */
      output;
   end;
run;
However, the results differ from the user's expectations. The %LET statement is executed immediately, while the DATA step is being compiled--before the data set is read. Therefore, the %LET statement executes regardless of the results of the IF condition. Even if the data set contains no observations where AGE is greater than 65, SR_CIT is always yes.
The solution is to set the macro variable's value by a means that is controlled by the IF logic and does not execute unless the IF statement is true. In this case, the user should use CALL SYMPUT, as in the following correct program:
%let sr_cit = no;
data senior;
   set census;
   if age > 65 then
   do;
      call symput ("sr_cit","yes");
    output;
   end;
run;
When this program is submitted, the value of SR_CIT is set to yesonly if an observation is found with AGE greater than 65. Note that the variable was initialized to no. It is generally a good idea to initialize your macro variables.

Resolving Macro Resolution Problems Occurring During DATA Step Compilation

In the previous example, you learned you had to use CALL SYMPUT to conditionally assign a macro variable a value in a DATA step. So, you submit the following program:
%let sr_age = 0;
data senior;
   set census;
   if age > 65 then
   do;
      call symput("sr_age",age);
      put "This data set contains data about a person";
      put "who is &sr_age years old."; /* ERROR */
   end;
run;
If AGE was 67, you would expect to see a log message like the following:
This data set contains data about a person
who is 67 years old.
However, no matter what AGE is, the following message is sent to the log:
This data set contains data about a person
who is 0 years old.
When the DATA step is being compiled, &SR_AGE is sent to the macro facility for resolution, and the result is passed back before the DATA step executes. To achieve the desired result, submit this corrected program instead:
%let sr_age = 0;
data senior;
   set census;
   if age > 65 then
   do;
      call symput("sr_age",age);
      stop;
   end;
run;

data _null_;
   put "This data set contains data about a person";
   put "who is &sr_age years old.";
run;
Note: Use double quotation marks in statements like PUT, because macro variables do not resolve when enclosed in single quotation marks.
Here is another example of erroneously referring to a macro variable in the same step that creates it:
data _null_;
   retain total 0;
   set mydata end=final;
   total=total+price;
   call symput("macvar",put(total,dollar14.2));
   if final then put "*** total=&macvar ***"; /* ERROR */
run;
When these statements are submitted, the following lines are written to the SAS log:
WARNING: Apparent symbolic reference MACVAR not resolved.

*** total=&macvar ***
As this DATA step is tokenized and compiled, the &causes the word scanner to trigger the macro processor, which looks for a MACVAR entry in a symbol table. Because such an entry does not exist, the macro processor generates the warning message. Because the tokens remain on the input stack, they are transferred to the DATA step compiler. During DATA step execution, the CALL SYMPUT statement creates the macro variable MACVAR and assigns a value to it. However, the text &macvarin the PUT statement occurs because the text has already been processed while the macro was being compiled. If you were to resubmit these statements and the macro would appear to work correctly, but the value of MACVAR would reflect the value set during the previous execution of the DATA step. This value can be misleading.
Remember that in general, the % and &trigger immediate execution or resolution during the compilation stage of the rest of your SAS code.
For more examples and explanation of how CALL SYMPUT creates macro variables, see Special Cases of Scope with the CALL SYMPUT Routine.

Solving Problems with the Autocall Facility

The autocall facility is an efficient way of storing and using production (debugged) macros. When a call to an autocall macro produces an error, the cause is one of two things:
  • an erroneous autocall library specification
  • an invalid autocall macro definition.
If the error is the autocall library specification and the MERROR option is set, SAS can generate any or all of the following warnings:
WARNING: No logical assign for filename
FILENAME.
WARNING: Source level autocall is not found or cannot be opened.
         Autocall has been suspended and OPTION NOMAUTOSOURCE has
         been set. To use the autocall facility again, set OPTION
         MAUTOSOURCE.
WARNING: Apparent invocation of macro
MACRO-NAME not resolved.
If the error is in the autocall macro definition, SAS generates a message like the following:
NOTE: Line generated by the invoked macro
"MACRO-NAME".

Fixing Autocall Library Specifications

When an autocall library specification causes an error, it is because the macro processor cannot find the member containing the autocall macro definition in the library or libraries specified in the SASAUTOS system option.
To correct this error, follow these steps.
  1. If the unresolved macro call created an invalid SAS statement, submit a single semicolon to terminate the invalid statement. SAS is then able to correctly recognize subsequent statements.
  2. Look at the value of the SASAUTOS system option by printing the output of the OPTIONS procedure or by viewing the OPTIONS window in the SAS windowing environment. (Or, edit your SAS configuration file or SAS autoexec file.) Verify each fileref or directory name. If you find an error, submit a new OPTIONS statement or change the SASAUTOS setting in the OPTIONS window.
  3. Check the MAUTOSOURCE system option. If SAS could not open at least one library, it sets the NOMAUTOSOURCE option. If NOMAUTOSOURCE is present, reset MAUTOSOURCE with a new OPTIONS statement or the OPTIONS window.
  4. If the library specifications are correct, check the contents of each directory to verify that the autocall library member exists and that it contains a macro definition of the same name. If the member is missing, add it.
  5. Set the MRECALL option with a new OPTIONS statement or the OPTIONS window. By default, the macro processor searches only once for an undefined macro. Setting this option causes the macro processor to search the autocall libraries for the specification again.
  6. Call the autocall macro, which includes and submits the autocall macro source.
  7. Reset the NOMRECALL option.
Note: Some host environments have environment variables or system-level logical names assigned to the SASAUTOS library; check your SAS companion for more information about how the SASAUTOS library specification is handled in your host environment.

Fixing Autocall Macro Definition Errors

When the autocall facility locates an autocall library member, the macro processor compiles any macros in that library member. It stores the compiled macros in the catalog containing stored compiled macros. For the rest of your SAS session, invoking one of those macros retrieves the compiled macro from the WORK library. Under no circumstances does the autocall facility use an autocall library member when a compiled macro with the same name already exists. Thus, if you invoke an autocall macro and discover you made an error when you defined it, you must correct the autocall library member for future use. Compile the corrected version directly in your program or session.
To correct an autocall macro definition in a windowing environment, do the following:
  1. Use the INCLUDE command to bring the autocall library member into the SAS Program Editor window. If the macro is stored in a catalog SOURCE entry, use the COPY command to bring the program into the Program Editor window.
  2. Correct the error.
  3. Store a copy of the corrected macro in the autocall library with the FILE command for a macro in an external file or with a SAVE command for a macro in a catalog entry.
  4. Submit the macro definition from the Program Editor window.
The macro processor then compiles the corrected version, replacing the incorrect compiled macro. The corrected, compiled macro is now ready to execute at the next invocation.
To correct an autocall macro definition in an interactive line mode session, do the following:
  1. Edit the autocall macro source with a text editor.
  2. Correct the error.
  3. Use a %INCLUDE statement to bring the corrected library member into your SAS session.
The macro processor then compiles the corrected version, replacing the incorrect compiled macro. The corrected, compiled macro is now ready to execute at the next invocation.

File and Macro Names for Autocall

When you want to use a macro as an autocall macro, you must store the macro in a file with the same name as the macro. Also, the file extension must be .sas (if your operating system uses file extensions). If you experience problems with the autocall facility, be sure the macro and filenames match and the file has the right extension when necessary.

Displaying Information about Stored Compiled Macros

To display the list of entries in a catalog containing compiled macros, you can use the Catalog window or the CATALOG procedure. The following PROC step displays the contents of a macro catalog in a SAS library identified with the libref MYSASLIB:
libname mysaslib
'SAS-data-library';
   proc catalog catalog=mysaslib.sasmacr;
      contents;
   run;
   quit;
You can also use PROC CATALOG to display information about autocall library macros stored in SOURCE entries in a catalog. You cannot use PROC CATALOG or the Explorer window to copy, delete, or rename stored compiled macros.
You can use the MCOMPILENOTE system option to issue a note to the log upon the completion of the compilation of any macro. For more information, see MCOMPILENOTE System Option.
In SAS 6.11 and later, you can use PROC SQL to retrieve information about all compiled macros. For example, submitting these statements produces output similar to the following output:
proc sql;
   select * from dictionary.catalogs
        where memname in ('SASMACR');
Output from PROC SQL Program for Viewing Compiled Macros
        Library   Member    Member    Object    Object                            Date      Object
        Name      Name      Type      Name      Type      Object Description      Modified  Alias
        -------------------------------------------------------------------------------------------
        WORK      SASMACR   CATALOG   FINDAUTO  MACRO                             05/28/96
        
        SASDATA   SASMACR   CATALOG   CLAUSE    MACRO     Count words in clause   05/24/96

        SASDATA   SASMACR   CATALOG   CMPRES    MACRO     CMPRES autocall macro   05/24/96

        SASDATA   SASMACR   CATALOG   DATATYP   MACRO     DATATYP autocall macro  05/24/96

        SASDATA   SASMACR   CATALOG   LEFT      MACRO     LEFT autocall macro     05/24/96
        
To display information about compiled macros when you invoke them, use the SAS system options MLOGIC, MPRINT, and SYMBOLGEN. When you specify the SAS system option MLOGIC, the libref and date of compilation of a stored compiled macro are written to the log along with the usual information displayed during macro execution.

Solving Problems with Expression Evaluation

The following macro statements use the %EVAL function:
Macro Statements That Use the %EVAL Function
%DO
%IF-%THEN
%SCAN
%DO %UNTIL
%QSCAN
%SYSEVALF
%DO %WHILE
%QSUBSTR
%SUBSTR
In addition, you can use the %EVAL function to specify an expression evaluation.
The most common errors that occur while evaluating expressions are the presence of character operands where numeric operands are required or ambiguity about whether a token is a numeric operator or a character value. Macro Expressions discusses these and other macro expression errors.
Quite often, an error occurs when a special character or a keyword appears in a character string. Consider the following program:
%macro conjunct(word= );
   %if &word = and or &word = but or &word = or %then   /* ERROR */
      %do %put *** &word is a conjunction. ***;

   %else
      %do %put *** &word is not a conjunction. ***;
%mend conjunct;
In the %IF statement, the values of WORD being tested are ambiguous — they could also be interpreted as the numeric operators AND and OR. Therefore, SAS generates the following error messages in the log:
ERROR: A character operand was found in the %EVAL function or %IF
       condition where a numeric operand is required. The condition
       was:word = and or      &word = but or       &word = or
ERROR: The macro will stop executing.
To fix this problem, use the quoting functions %BQUOTE and %STR, as in the following corrected program:
%macro conjunct(word= );
   %if %bquote(&word) = %str(and) or %bquote(&word) = but or
          %bquote(&word) = %str(or) %then
      %do %put *** &word is a conjunction. ***;

   %else
      %do %put *** &word is not a conjunction. ***;
%mend conjunct;
In the corrected program, the %BQUOTE function quotes the result of the macro variable resolution (in case the user passes in a word containing an unmatched quotation mark or some other odd value). The %STR function quotes the comparison values AND and OR at compile time, so they are not ambiguous. You do not need to use %STR on the value BUT, because it is not ambiguous (not part of the SAS or macro languages). See Macro Quoting for more information about using macro quoting functions.