Ren'Py Sayer is not a function or I have made a fubar

mickydoo

Fudged it again.
Game Developer
Jan 5, 2018
2,446
3,548
I was just making a scene when in renpy when I was getting this error

Sayer n is not a function

The "n" being defined at the start of the game as
define n = Character("Nicky", who_bold=True, color="#FF0066")

Which has worked for dozens of lines of her dialog until now. Upon googling I got this from lemasoft with someone who the same issue with Andre.

"Do you have any other variables named "andre" that have any values different from Character"

That was their issue, looking at my code to see what I had done between the last update and this one, I was thinking, I wouldn't of used "n" as a variable, but alas I have, about 12 times.
I have used -
$ n = renpy.random.random()

This is for a major lolz bit in the game, took me ages to get it to work.

(Edit - I have just thought of this as I hit preview)
I have re defined Nicky to a different letter and it has fixed it for here, but will doing this fuck up anything prior?
 

mickydoo

Fudged it again.
Game Developer
Jan 5, 2018
2,446
3,548
anne O'nymous
It is defined at the start of the script as n, then the random variable, then after that I re defined it as ni. So both should work, hopefully anyway.
 

anne O'nymous

I'm not grumpy, I'm just coded that way.
Modder
Donor
Respected User
Jun 10, 2017
10,302
15,172
anne O'nymous
It is defined at the start of the script as n, then the random variable, then after that I re defined it as ni. So both should work, hopefully anyway.
You redefine it this way, $ ni = Character("Nicky", who_bold=True, color="#FF0066"), so not by using the define statement, right ?
In this case it shouldn't generate problems ; unless you forget that ni is used, like you did for n :D
 

mickydoo

Fudged it again.
Game Developer
Jan 5, 2018
2,446
3,548
You redefine it this way, $ ni = Character("Nicky", who_bold=True, color="#FF0066"), so not by using the define statement, right ?
In this case it shouldn't generate problems ; unless you forget that ni is used, like you did for n :D
No I redfined using define, i just changed it to what you said and it's still working fine.

In my defence, I am easily excitable. i would not of deliberately used a single letter to define or default anything because of name conflicts, the random did not occur to me, I was too busy tapping myself on the back telling myself how clever I was getting the randoms to work, the $ n = renpy.random.random() is just a copy and paste, didn't even really notice the n.

As always anne O'nymous thank you, my game would still be in the noob box without your help.
 

anne O'nymous

I'm not grumpy, I'm just coded that way.
Modder
Donor
Respected User
Jun 10, 2017
10,302
15,172
No I redfined using define, i just changed it to what you said and it's still working fine.
The "problem" of define is that "doing it later" have no meaning for this statement. Ren'py will execute it at init time whatever the place you put it in the code.
Consider the following (really evil) code :
Code:
label start:
   if myVar == 12:
      "It's magic :D"
   "END"
label myLabel:
   return
   label .subLabel:
      while True == False:
          if True == False:
             define myVar = 12
The assignation look like it depend of an if condition that can not be True, in a while loop that will never be executed, inside a sub label that is never reached, itself put in a label never called nor jumped to. So, by default you think that the assignation will never happen. Yet, myVar will have the value 12 even before you hit the "start" button.

This said, practically speaking, it will works whatever you use the define way, or the $ one. But letting you do it with define could lead to problems later. Not with this particular case, but who know what you'll have to redefine one day. You'll innocently do it with define, think that everything is ok... but broke all the start of your game without realizing it.


In my defence, I am easily excitable.
Don't worry, we are all like this sometimes. I remember, when I wrote my first backup system in the previous century. It was working really great and I was really happy about it... Until I had to retrieve some data and I discovered that yes, the archive were all tested and validated as not corrupted... but it was the original archive that I tested, not the backup copy...
So, yeah, we can all be really excitable and forget to verify the small details because of this.


As always anne O'nymous thank you, my game would still be in the noob box without your help.
I just give advice and correct few errors times to times, it's all. Everything else is made by you. Let's say that I help the game to be like you imagine it, but it's still your imagination that made the best part.
 
  • Like
Reactions: mickydoo

Zawkian_Puppy

The Cheesy pup
Game Developer
Sep 12, 2019
147
222
SOLUTION

if you having this problem just name the sayer differently. for example

in my game the sayer was named Ava, using "ava" as the sayer word. i just named it to "av"
 

DanStory

Newbie
Sep 30, 2021
50
66
A long time not seen classical. And you figured it right.




It depend how you did it, but normally it will be alright.
hello i have the same probem but after i restart the project, it work normally..
im not change anything, i just restart the project
my question, is there any possible that bug reappeared when i build the game and play it?
 

anne O'nymous

I'm not grumpy, I'm just coded that way.
Modder
Donor
Respected User
Jun 10, 2017
10,302
15,172
hello i have the same probem but after i restart the project, it work normally..
im not change anything, i just restart the project
my question, is there any possible that bug reappeared when i build the game and play it?
Hmm, you should be more precise.
You've a "[whatever] is not a valid sayer" error, restart the game, and don't have the error anymore...
But do you mean that you return to the main menu page, start again, and the error disappear even after the point where you initially had it ?
Or do you mean that you use ctrl + r to restart the game, from the current point ?
 

DanStory

Newbie
Sep 30, 2021
50
66
Hmm, you should be more precise.
You've a "[whatever] is not a valid sayer" error, restart the game, and don't have the error anymore...
But do you mean that you return to the main menu page, start again, and the error disappear even after the point where you initially had it ?
Or do you mean that you use ctrl + r to restart the game, from the current point ?
when using ctrl + r my project still error like sayer not function or string
and then i try to quit the project and reopen it and the error is gone
im not change anything just quit and then reopen the project from beginning and solved until the story end
is there any possible that bug reappeared when i build the game and play it?
 
Last edited:

anne O'nymous

I'm not grumpy, I'm just coded that way.
Modder
Donor
Respected User
Jun 10, 2017
10,302
15,172
when using ctrl + r my project still error like sayer not function or string
and then i try to quit the project and reopen it and the error is gone
Ok.

i guess (not having the whole game code I can't do more), that it's because the sayer is redefine during the init phase of the game.
So, to answer your answer, yes, the problem will reappeared when you build the game and play it.


im not change anything just quit and then reopen the project from beginning and solved until the story end
Superpowered had the same kind of issue in the past. One formula, of one event, was redefining the variable used for one sayer, yet just under some particular conditions.
I guess that it's the same thing with you, what explain why there's time when the error don't appear.

When the error appear, you've an error message saying "Exception: Sayer [SOMETHING] is not a function or string.".
Track every occurrence of this "[SOMETHING]" in your game, until you find the moment where its value is changed.
It's where the error lie, and what you've to change accordingly to what is said in the start of this thread.
 

79flavors

Well-Known Member
Respected User
Jun 14, 2018
1,576
2,203
To recap what's been said above...
At the core of this is the fact that it's possible to completely "reinvent" a variable while your script is running.

Imagine this:

Python:
default my_var = 0

label start:

    scene black with fade

    "*** START ***"
    "My var is currently '[my_var]' (a number)."

    $ my_var = "Some text"
    "My var is currently '[my_var]' (a string)."

    $ my_var = ["Value 1", "Value 2"]
    "My var is currently '[my_var]' (a list/array)."

    $ my_var = Character("Eileen")
    "My var is currently '[my_var.name]' (a Character)."

    $ my_var = 42
    "My var is currently '[my_var]' (a number again)."

    "*** THE END ***"
    return

So when you write code like:

Python:
define e = Character("Eileen")

default var1 = 1
default var2 = 2

label start:

    $ e = var1 + var2

    e "Says nothing (because it crashes)."

    "THE END"
    return

It's the same thing. The variable e (which was a Character() ) becomes a number variable.

The whole "Sayer var1 is not a function" is just another way of it telling you that "Variable var1 is not a Character() object".
Which can only happen if you've reused the variable name without realizing it.

The bigger problem though is how you fix it...

Let's assume the variable is called e. You now have to realize that you now have people out there with save game files that include e = 0 or e = 42 or whatever. It's been overwritten by some other value that the game is incapable of using in place of a Character().

It would be very tempting to just find the place in the code where you've mistakenly done something like $ e = 0 and "fix" it, probably by renaming the variable to something else i maybe or num to read $ num = 0... then change all the other places you've incorrectly used it to num too.

Except... that doesn't affect the save files.
Player-X comes along, load their save file... and e is again overwritten by 0 (or whatever).
... and now e is no longer a Character() again. D'oh.

Now there are ways around this (which I won't go into now).

But the more robust solution is to rename the original character to something like ei or e2 or sis.

It's not ideal... and you've going to have to go back and change that character's ID on every single line of dialogue that character speaks (an editor with "change all" can make it a little easier ... CHANGE ALL " e \"" to " e2 \"" (4 spaces, character E, 1 space, doublequote)... being only one possible way). But you risk missing a some lines or inadvertently changing something you hadn't planned to with mass changes though.

But as much work as it is... it's still easier than worrying about people with save files that will break the game if used.

I'd like to also point out the most common instance of this happening is people who write code like this:

Python:
define mc = Character("Unnamed")

label start:

    scene black with fade
    "*** THE START ***"

    $ mc = renpy.input("What is the character's name? (Enter for 'Tom')", exclude="[]{}")
    $ mc = mc.strip()
    if mc == "" then
        $ mc = "Tom"

    "*** THE END ***"
    return

Which replaces a Character() variable with a string variable.
And the only reason the developer doesn't notice is because sayer works with both String and Character() objects. Generally the first time people notice this is when they realize they've set a color for the character, but it instead shows in the default color (which is what it uses, when it can't access all those extra Character() properties that were lost when it was replaced by a string object).
 
Last edited:

Turning Tricks

Rendering Fantasies
Game Developer
Apr 9, 2022
946
2,026
Just wanted to necro this thread because I have an issue with my current release where some people are getting this error ("Sayer gilf1 is not a function or string")

I can't duplicate the error on my end, and I just went through all my code searching for any instance of "gilf1", but it doesn't look like I made the most common error of using the same name for two variables. I also have no instances of a custom name script making the mistake 79flavors mentions in the post above this one. (I used "gilf1_name" .. or basically "_name" on any character for that situation)

My gut feeling is that the error is being caused by people using saves from my Initial Release (Prologue) . The character "gilf1" wasn't defined in that release.

It seems odd to me though, that the several people who have reported this error, all have it happen with gilf1, when I actually added maybe 6 new characters in total, all with their own defines. And yet, I am not getting any errors with those variable names.

Can anyone enlighten me on what is causing this maybe? Also, can i fix it? Or should I just tell the players to delete their saves and persistent files and start a new game?

I'm also worried about future save compatibility. My next release should be OK as i have already coded in the names for several characters I plan on introducing, but what happens when I need to add a new character? Will making a new character define break people's saves?

Right now, it's not a huge issue for people to start over, as the prologue was basically an introduction and there really wasn't any forks or choices that needed to be saved. But starting from this release, the game has a lot of choices that need to be tracked now.

Slowly learning this stuff, lol :p
 

79flavors

Well-Known Member
Respected User
Jun 14, 2018
1,576
2,203
I'm guessing here, but my answer feels like it's in the right sort of place...

My recollection is that it tends to end up being a mixture of define gilf1_name = Character() and $ gilf1_name = "{value}"

Any variable defined with define is temporary. It exists while the game is running, but is lost when the player quits. Which is fine, because next time the player runs the game, the variable is created again.

The problem happens when you create a "normal" variable with the same name. Perhaps you do something like $ gilf1_name = "Stacy". The problem is that gilf1_name is now a string rather than a Character() object. Worse, it is also saved to the save files. You load a game... and gilf1_name is overwritten with whatever the value you you set it to, even if you've since removed that code from your game... it's in the save file, therefore it loads it.

You have a couple of options.

By far the easiest is to abandon the use of gilf1_name in your code. Changed everywhere that says define gilf1 = Character() to define gg1 = Character() or something. Then go through you code with a fine tooth comb making sure there isn't a $default gg1 = ... or $ gg1 = anywhere in your code. If there is, you introduce the problem again.

If you are going to regularly rename the gg1 character, it should look like this:

Python:
default gg1_name = "???"
define gg1 = Character("[gg1_name]")

label start:

    $ gg1_name = "Stacy"

You can change the value of gg1_name, but never change gg1 (since it is a define).


A slightly less common solution would be to abandon the use of the Character() object completely.

RenPy has this thing where you can just type in the name of a character on each and every line that character has dialogue.

So for example:

Python:
label start:

    "Stacy" "Hello, my name is Stacy."
    "Stacy" "I'll be your .... blahh, blahh..."

In this example, a character is never created. Instead a temporary name is used each and every time the character speaks. It's especially handy when dealing with characters who you are never going to meet again ("Waiter" maybe or "Taxi Driver").

It has the advantage that because there is no variable, where's very little chance you are going to accidently conflict with a variable you created in a previous release.
 

Turning Tricks

Rendering Fantasies
Game Developer
Apr 9, 2022
946
2,026
I'm guessing here, but my answer feels like it's in the right sort of place...

My recollection is that it tends to end up being a mixture of define gilf1_name = Character() and $ gilf1_name = "{value}"

Any variable defined with define is temporary. It exists while the game is running, but is lost when the player quits. Which is fine, because next time the player runs the game, the variable is created again.

The problem happens when you create a "normal" variable with the same name. Perhaps you do something like $ gilf1_name = "Stacy". The problem is that gilf1_name is now a string rather than a Character() object. Worse, it is also saved to the save files. You load a game... and gilf1_name is overwritten with whatever the value you you set it to, even if you've since removed that code from your game... it's in the save file, therefore it loads it.

You have a couple of options.

By far the easiest is to abandon the use of gilf1_name in your code. Changed everywhere that says define gilf1 = Character() to define gg1 = Character() or something. Then go through you code with a fine tooth comb making sure there isn't a $default gg1 = ... or $ gg1 = anywhere in your code. If there is, you introduce the problem again.

If you are going to regularly rename the gg1 character, it should look like this:

Python:
default gg1_name = "???"
define gg1 = Character("[gg1_name]")

label start:

    $ gg1_name = "Stacy"

You can change the value of gg1_name, but never change gg1 (since it is a define).


A slightly less common solution would be to abandon the use of the Character() object completely.

RenPy has this thing where you can just type in the name of a character on each and every line that character has dialogue.

So for example:

Python:
label start:

    "Stacy" "Hello, my name is Stacy."
    "Stacy" "I'll be your .... blahh, blahh..."

In this example, a character is never created. Instead a temporary name is used each and every time the character speaks. It's especially handy when dealing with characters who you are never going to meet again ("Waiter" maybe or "Taxi Driver").

It has the advantage that because there is no variable, where's very little chance you are going to accidently conflict with a variable you created in a previous release.

I think you may have misunderstood my post above.

The error that my users are getting is this...

Exception: Sayer gilf1 is not a function or string
So, the first thing I did was root through all my code to see if i had used "gilf1" as a variable somewhere else, which i didn't. I double and triple checked that.

For each of my characters, I use the same basic syntax for constructing their important variables.

gilf1 = the character define for the first GILF in the game. Only used for the define.
gilf1_name is the name variable I use. There are no errors being thrown for that variable

I have several others as well, all distinctive and starting with gilf1 but all unique variables like "gilf1_look1" or "gilf1_touch1" .. etc.

So, as far as i can see, it's definitely not a case of the variable gilf1 being used as a character define, then being changed later on. The only thing I can see is that people who used my prologue save, are the only ones getting this error. And in the prologue release, I didn't have any gilf1 variables at all. Some of my patrons have also reported that doing what i suggested (deleting the persistent file) has fixed things for them when they restart the game.

I'm just confused why it's causing an issue in the first place and it's making me nervous about adding new characters in the future.
 

79flavors

Well-Known Member
Respected User
Jun 14, 2018
1,576
2,203
I think you may have misunderstood my post above.

You may well be right.
This is the downside of trying to diagnose code based on assumptions.

The only thing I would say is that you've checked your current code and it's fine. Which is not to say something didn't go wrong temporarily at some point in the past.

I would recommend asking someone who's had problems with the error to send you a save file. Load that save and have a look at the variables using the developer menu (SHIFT+D -> Variable Viewer). Or go full on, and use Anne's Extended Variable Viewer to go a little deeper.

It might be I'm completely mistaken here. But you'll need a "real world" save file or two to verify your assumptions.
 
  • Like
Reactions: Turning Tricks

anne O'nymous

I'm not grumpy, I'm just coded that way.
Modder
Donor
Respected User
Jun 10, 2017
10,302
15,172
Can anyone enlighten me on what is causing this maybe? Also, can i fix it? Or should I just tell the players to delete their saves and persistent files and start a new game?
The only possibility is that "gilf1" is in the save file. Then loading this save overwrite the one you declared with define (variables.rpy:24). But why is it in the save file, I don't know.


I'm also worried about future save compatibility. My next release should be OK as i have already coded in the names for several characters I plan on introducing, but what happens when I need to add a new character? Will making a new character define break people's saves?
As long as you don't use the same name than a variable that existed previously, there's no reason for a problem to happen.

You can take a look at my save compatibility how-to (link in my signature), or 79flavors' intro to Ren'Py variables (link in his signature), both should tell you everything you need to know regarding why the error you get shouldn't have happened... What don't really help, I know :(
 

Turning Tricks

Rendering Fantasies
Game Developer
Apr 9, 2022
946
2,026
The only possibility is that "gilf1" is in the save file. Then loading this save overwrite the one you declared with define (variables.rpy:24). But why is it in the save file, I don't know.




As long as you don't use the same name than a variable that existed previously, there's no reason for a problem to happen.

You can take a look at my save compatibility how-to (link in my signature), or 79flavors' intro to Ren'Py variables (link in his signature), both should tell you everything you need to know regarding why the error you get shouldn't have happened... What don't really help, I know :(
This is really strange indeed. I might have to dig into my old release and see if I had something in there I forgot about. It's definitely not in the current code. I'll also try 79flavors advice and ask one of the people who had the issue to send me a save file. And I will go over your links AON again. I read them a while back, but I need a refresher.

After Christmas though! I'm officially not thinking about my project for the next 3 or 4 days, at least. And we have a huge winter storm about to hit us, so I am nesting and catching up on a lot of other games I haven't been able to play in ages.

Thanks both of you.

EDIT: Just had a thought as well, based on discussions with other devs... it's quite possible that the few people reporting this error were messing around in the code with the console or those save editors. Most of them won't fess up to that and a few devs have told me they wasted lots of troubleshooting time on some bug reports that turned out to be caused by mods and save editors.
 

anne O'nymous

I'm not grumpy, I'm just coded that way.
Modder
Donor
Respected User
Jun 10, 2017
10,302
15,172
EDIT: Just had a thought as well, based on discussions with other devs... it's quite possible that the few people reporting this error were messing around in the code with the console or those save editors.
I thought about it, but how would they had come to this "gilf1" name ?
That an error come from them putting a wrong value into an existing variable, it's totally possible. But that they create a variable out of nowhere feel less likely to happen.
 

Turning Tricks

Rendering Fantasies
Game Developer
Apr 9, 2022
946
2,026
I thought about it, but how would they had come to this "gilf1" name ?
That an error come from them putting a wrong value into an existing variable, it's totally possible. But that they create a variable out of nowhere feel less likely to happen.
True.. it's not likely they came up with gilf1 in a vacuum.

Some guy told me the other day that he used some utility that plotted out logic paths or something. I have a feeling it's a script someone wrote to track all the variables and supposedly show you the proper choices to reach a certain scene. gilf1 was one of the 3 characters in the last scene of the game and you only got to see one version of it, depending of your choices. I was just thinking maybe they wanted to force the second version of that scene and messed up somehow.

In any case, that's a moot point. After Xmas, I'll crack open my last release and take a look-see then do some research.