Invalid context id specified context

Invalid context id specified context

by Steve Lawrence -
Number of replies: 41

Hi,

I'm back with a continued tale of determination and woe.  

I had all sorts of issues trying to upgrade from 1.9 -> 2.2 which were solved (or so I thought) by going 1.9 -> 2.1 -> 2.2.  When I tried this it worked first time on a copy of our site.  

A couple of weeks later we arranged to take the site offline for a day to update the site for real.  All went well, or so we thought.  

It turns out everything appeared to be working except when you try to review any quiz attempt.  You get the following error.

Coding error detected, it must be fixed by a programmer: Invalid context id specified context::instance_by_id()

So I rolled back and continued testing.  It seems that I can upgrade to 2.1 without any problems.  No errors during upgrade, everything works fine.  However, when I upgrade to 2.2 I get this same error on all quiz attempts.

Microsoft IIS7.5/Microsoft SQL Server 2008 R2

1.9.19 -> (2.0.10 ->) 2.1.9 -> 2.2.6 ... -> 2.3.3 (ideally).

(I've tried it with and without 2.0 and it seems to make no difference.)

-> 2.1 all fine

2.1 -> 2.2 error.

Please help, I'm starting to dream about Moodle upgrades...

 

Average of ratings:Useful (1)
In reply to Steve Lawrence

Re: Invalid context id specified context

by Howard Miller -
Picture of Core developers Picture of Documentation writers Picture of Particularly helpful Moodlers Picture of Peer reviewers Picture of Plugin developers

Did you do this on your 1.9 site....

http://docs.moodle.org/23/en/Verify_Database_Schema

The upgrading docs do recommend it but it's often sufficiently scary to be avoided. Making sure your 1.9 site is rock-solid before you even think about the upgrade is the sensible starting point.

Failing that, it's worth posting a link to this in the quiz forum as Tim will have a better insight into what might be causing that.

In reply to Howard Miller

Re: Invalid context id specified context

by Steve Lawrence -

I didn't but I will have a look at it today.  

It just seems odd that issues comes between 2.1 and 2.2 instead of the big change in 2.1.  And also that the first time I did it it worked.  I would understand if only a few quizzes or attempts (i.e. those added after the first upgrade test) would fail, but it seems to be all of them.

Oh well, into the schema breach...

 

 

In reply to Steve Lawrence

Re: Invalid context id specified context

by Howard Miller -
Picture of Core developers Picture of Documentation writers Picture of Particularly helpful Moodlers Picture of Peer reviewers Picture of Plugin developers

It may well be nothing to do with it but it's worth having a clean start.

In reply to Steve Lawrence

Re: Invalid context id specified context

by Tim Hunt -
Picture of Core developers Picture of Documentation writers Picture of Particularly helpful Moodlers Picture of Peer reviewers Picture of Plugin developers

Could you set Debugging to developer level, then we shoud get a complete stack trace with the error message, which would let us see where the error is being triggered.

In reply to Tim Hunt

Re: Invalid context id specified context

by Steve Lawrence -

There appears to be no difference between the current 1.9 site and a site with a clean database (schema-wise).  I'm using MS SQL so I had to figure out my own way to compare but it seems legit.

Stack trace:
  • line 4883 of \lib\accesslib.php: coding_exception thrown
  • line 6910 of \lib\accesslib.php: call to context::instance_by_id()
  • line 703 of \question\engine\questionusage.php: call to get_context_instance_by_id()
  • line 345 of \question\engine\datalib.php: call to question_usage_by_activity::load_from_records()
  • line 78 of \question\engine\lib.php: call to question_engine_data_mapper->load_questions_usage_by_activity()
  • line 437 of \mod\quiz\attemptlib.php: call to question_engine::load_questions_usage_by_activity()
  • line 457 of \mod\quiz\attemptlib.php: call to quiz_attempt->__construct()
  • line 467 of \mod\quiz\attemptlib.php: call to quiz_attempt::create_helper()
  • line 47 of \mod\quiz\review.php: call to quiz_attempt::create()
And this at the very bottom of the page:

Warning: mssql_free_result(): 122 is not a valid MS SQL-result resource in F:\inetpub\MOODLE\MoodleUpgrade\lib\dml\mssql_native_moodle_recordset.php on line 75

In reply to Steve Lawrence

Re: Invalid context id specified context

by Tim Hunt -
Picture of Core developers Picture of Documentation writers Picture of Particularly helpful Moodlers Picture of Peer reviewers Picture of Plugin developers

OK, so the question_usages.contextid column contains a vaue that does not correspond to any context. A query like

SELECT *
FROM mdl_question_usages qu
LEFT JOIN mdl_quiz_attempts quiza ON quiza.uniqueid = qu.id
LEFT JOIN mdl_context ctx ON ctx.id = qu.contextid
WHERE ctx.id IS NULL

will find all the problem rows for you.

The question_usage.contextid should be the contextid for the quiz the attempt belongs to.

Average of ratings:Useful (1)
In reply to Tim Hunt

Re: Invalid context id specified context

by Steve Lawrence -

 

It returns 26697 rows (I would guess that's ALL attempts).

All rows appear as below.

I get the same result with the 2.1 database but that doesn't give the original error and attempts can be reviewed.  (1.9 does not contain that table.)

In reply to Steve Lawrence

Re: Invalid context id specified context

by Steve Lawrence -

Actually, that's not true, sorry, my mistake.  Not all rows contain all NULLs as above, many of the rows contain data, but ALL contextids are NULL.  I get 5530 rows where everything is NULL as above.

In reply to Steve Lawrence

Re: Invalid context id specified context

by Steve Lawrence -

The obvious questions now (to me at least) are:

Why did this happen? (Why didn't the conversion put in the correct contextids - I added a new atempt in 2.2 and it added the contextid and displayed the attempt review without error.)

Why doesn't it affect 2.1? (Presumably the code for 2.1 doesn't use the contextid but why then was it included in the conversion to 2.1?)

Can we fix it?  (Even if we have to write a query ourselves to extract the correct data from the 1.9 database to put into the 2.2 database - I say we/ourselves but of course I'm relying on you heavily to do/help with that. smile)

Many thanks for the help so far.

In reply to Steve Lawrence

Re: Invalid context id specified context

by Tim Hunt -
Picture of Core developers Picture of Documentation writers Picture of Particularly helpful Moodlers Picture of Peer reviewers Picture of Plugin developers

The ugprade should have put in the correct context id, and as you say, it must have done because it worked in 2.1. Something odd must have happened during the upgrade to 2.2, but I cannot think what.

Anyway, it should be fixable. This query should find the problem rows

SELECT qu.*, ctx.*
FROM o_question_usages qu
JOIN o_quiz_attempts quiza ON quiza.uniqueid = qu.id
JOIN o_quiz quiz ON quiz.id = quiza.quiz
JOIN o_course_modules cm ON cm.instance = quiz.id
JOIN o_modules mod ON cm.module = mod.id AND mod.name = 'quiz'
LEFT JOIN o_context ctx ON ctx.instanceid = cm.id AND ctx.contextlevel = 70
WHERE qu.contextid <> ctx.id

If that seems to be working, I assuem you will be able to edit that to do the appropriate update. (That is the sort of thing where you should probably backup the database first.)

If that is not enouh information, get back to me.

Average of ratings:Useful (1)
In reply to Tim Hunt

Re: Invalid context id specified context

by Steve Lawrence -

That didn't work as above but I replaced o_ with mdl_ (unless I'm missing something) but even that returned 0 rows.

Also note that I got the same NULL contextid for all rows after the 2.1 upgrade.  But that worked okay until 2.2.

In reply to Steve Lawrence

Re: Invalid context id specified context

by Tim Hunt -
Picture of Core developers Picture of Documentation writers Picture of Particularly helpful Moodlers Picture of Peer reviewers Picture of Plugin developers

Sorry, o_ is the database prefix in my test database. Replacing it with whatever you are using was correct.

I see, you are saying that qu.contextid is null. Well, then we need to change the query to

WHERE qu.contextid IS NULL OR qu.contextid <> ctx.id

If that still does not give any results, then, one at a time, starting from the bottom, replace each plain JOIN with INNER JOIN until you do get some results.

Average of ratings:Useful (1)
In reply to Tim Hunt

Re: Invalid context id specified context

by Steve Lawrence -

Okay, that worked.  Now I'm only vaguely aware of what I'm looking at but should the id we have there (from quiz_attempts?) be the contextid in question_usages?

 

In reply to Steve Lawrence

Re: Invalid context id specified context

by Steve Lawrence -

Okay, I give up.  My SQL is still too basic to know how to put that into an update (I can see WHAT needs to be done but just can't get my head around the HOW).  Normally I'd love to sit down and play around with it until I get it (and I probably would) but I'm pretty busy with running the rest of the network and rarely get the time to sit and play with this sort of stuff.

Any help on the update query would be much appreciated, thank you.

In reply to Tim Hunt

Re: Invalid context id specified context

by Steve Lawrence -

I don't understand this (amongst other stuff).  When I run 

select * from mdl_question_usages

I get 26698 rows (5530 of which have preferredbehavior = 'to_be_set_later'). (1 of which isn't a NULL contextid because I added an attempt later.)

But when I run your query I get 27728 rows (with no 'to_be_set_later').

How can the query return more rows than there are in the table and why does preferredbehavior change?

In reply to Steve Lawrence

Re: Invalid context id specified context

by Steve Lawrence -

Wait a minute...

UPDATE mdl_question_usages
SET mdl_question_usages.contextid = ctx.id
FROM mdl_question_usages qu
JOIN mdl_quiz_attempts quiza ON quiza.uniqueid = qu.id
JOIN mdl_quiz quiz ON quiz.id = quiza.quiz
JOIN mdl_course_modules cm ON cm.instance = quiz.id
JOIN mdl_modules mod ON cm.module = mod.id AND mod.name = 'quiz'
LEFT JOIN mdl_context ctx ON ctx.instanceid = cm.id AND ctx.contextlevel = 70

seems to have worked.  I still have 5600 rows where contextid is NULL but random spot-check attempt reviews appear to all be working!

In reply to Steve Lawrence

Re: Invalid context id specified context

by Tim Hunt -
Picture of Core developers Picture of Documentation writers Picture of Particularly helpful Moodlers Picture of Peer reviewers Picture of Plugin developers

Sorry I was not around while you were working this out.

That does look like the right update query.

I don't know why you still have some rows with NULL. It could be that they are 'orphaned' data. That is, the attempt data is still there, but the corresponding quiz was deleted, or something like that.

Also, I still can't think how your site got into that state. The upgrade should just work automatically. Still I am glad you were able to sort it out. (Fingers crossed.)

In reply to Tim Hunt

Re: Invalid context id specified context

by Steve Lawrence -

Many thanks for the help.  I have some teachers testing at the minute and if it looks good to them I'm going to try another test upgrade from the beginning with this query and if that also works again I'm going for upgrading the live site again.  Fingers crossed here too.

In reply to Steve Lawrence

Re: Invalid context id specified context

by Steve Lawrence -

Well, I have another apology to make - it seems that I was mistaken about there being no errors during the upgrade.  With debug mode on I now see this that seems to be the cause.

Debug info: The statement has been terminated.

UPDATE mdl_question_usages SET contextid = (
SELECT ctx.id
FROM mdl_context ctx
JOIN mdl_course_modules cm ON cm.id = ctx.instanceid AND cm.module = 13
JOIN mdl_quiz_attempts quiza ON quiza.quiz = cm.instance
WHERE ctx.contextlevel = 70
AND quiza.uniqueid = mdl_question_usages.id
)

[array (
)]

Stack trace:
  • line 397 of \lib\dml\moodle_database.php: dml_write_exception thrown
  • line 255 of \lib\dml\mssql_native_moodle_database.php: call to moodle_database->query_end()
  • line 668 of \lib\dml\mssql_native_moodle_database.php: call to mssql_native_moodle_database->query_end()
  • line 6190 of \lib\db\upgrade.php: call to mssql_native_moodle_database->execute()
  • line 1418 of \lib\upgradelib.php: call to xmldb_main_upgrade()
  • line 277 of \admin\index.php: call to upgrade_core()

This happens during the System update - there was a database error but if you continue everything else works which is why I previously disgarded it - my mistake.So if I run the query directly (SQL Management Studio) I get:

Msg 512, Level 16, State 1, Line 1
Subquery returned more than 1 value. This is not permitted when the subquery follows =, !=, <, <= , >, >= or when the subquery is used as an expression.
The statement has been terminated.

If I run just the select part:

SELECT ctx.id
FROM mdl_context ctx
JOIN mdl_course_modules cm ON cm.id = ctx.instanceid AND cm.module = 13
JOIN mdl_quiz_attempts quiza ON quiza.quiz = cm.instance
WHERE ctx.contextlevel = 70
AND quiza.uniqueid = mdl_question_usages.id

I get 

Msg 4104, Level 16, State 1, Line 6
The multi-part identifier "mdl_question_usages.id" could not be bound.

Does this help?

In reply to Steve Lawrence

Re: Invalid context id specified context

by Tim Hunt -
Picture of Core developers Picture of Documentation writers Picture of Particularly helpful Moodlers Picture of Peer reviewers Picture of Plugin developers

Well, at least this now gives us a logical explanation for what went wrong, which is reassuring in its way.

The reason you cannot run the subquery on its own is because it refers to data from the outer query. We need to try a query like:

SELECT qu.id, COUNT(ctx.id)
FROM mdl_question_usages qu 
JOIN mdl_quiz_attempts quiza ON quiza.uniqueid = qu.id
JOIN mdl_course_modules cm ON quiza.quiz = cm.instance AND cm.module = 13
JOIN mdl_context ctx ON cm.id = ctx.instanceid AND ctx.contextlevel = 70
GROUP BY qu.id
HAVING COUNT(ctx.id) > 1

That should list all the mdl_question_usages.id that might lead to that error. 

Then, once you have done that, you can run the subquery

SELECT ctx.id
FROM mdl_context ctx
JOIN mdl_course_modules cm ON cm.id = ctx.instanceid AND cm.module = 13
JOIN mdl_quiz_attempts quiza ON quiza.quiz = cm.instance
WHERE ctx.contextlevel = 70 
AND quiza.uniqueid = {put question_usage.id here}

To explore further.

In reply to Tim Hunt

Re: Invalid context id specified context

by Steve Lawrence -

Okay thanks.

The first gave 6644 rows.  Running the second on several of them gave 2 rows each time.  Most of them seem to be different although a couple gave the same two.

In reply to Steve Lawrence

Re: Invalid context id specified context

by Tim Hunt -
Picture of Core developers Picture of Documentation writers Picture of Particularly helpful Moodlers Picture of Peer reviewers Picture of Plugin developers

Actually, with the second query, can you change it to SELECT *

Somewhere along the chain -> quiz_attempts -> course_modules -> contexts we are going from one row to two rows, even though the links should be unique at each point.

We need to find where the duplication happens.

In reply to Tim Hunt

Re: Invalid context id specified context

by Steve Lawrence -

Sounds good... how do we do that?

In reply to Steve Lawrence

Re: Invalid context id specified context

by Tim Hunt -
Picture of Core developers Picture of Documentation writers Picture of Particularly helpful Moodlers Picture of Peer reviewers Picture of Plugin developers

Sorry, my last post was rather brief. To explain better. In the

SELECT ctx.id
FROM mdl_context ctx
JOIN mdl_course_modules cm ON cm.id = ctx.instanceid AND cm.module = 13
JOIN mdl_quiz_attempts quiza ON quiza.quiz = cm.instance
WHERE ctx.contextlevel = 70 
AND quiza.uniqueid = {put question_usage.id here}

query, change the first line to SELECT *, so it shows all the data from all the tables.

Then, as you look at the table, the first columns, which come from mdl_context, will have different values in each rows; and the last columns, which come from quiz_attempts, will probably have identical values in each row.

Somewhere inbetween, it will change between those two behaviours, and where that happens may tell us something.

Average of ratings:Useful (1)
In reply to Tim Hunt

Re: Invalid context id specified context

by Steve Lawrence -

Okay, gotcha.

Columns that are different:

id, instanceid, path, depth, id, course, section, idnumber, added

Everything else is the same:

contextlevel, module, instance, score (and everything after that).

Is that any use? 

In reply to Steve Lawrence

Re: Invalid context id specified context

by Tim Hunt -
Picture of Core developers Picture of Documentation writers Picture of Particularly helpful Moodlers Picture of Peer reviewers Picture of Plugin developers

So, the problem seems to be that we have rows in the course_modules table where module and instance are the same? We can confirm that by doing

SELECT module, instance, count(1)
FROM mdl_course_modules
GROUP BY module, instance
HAVING count(1) > 1

That is as if the same quiz is in two different courses, which should be impossible. How many different coures_module rows are there like that? How many different course ids? Do all those courses exist?

I am hoping that some of those rows refer to a non-existant course, or somehting like that. Then we will know those are the garbage ones, and we can safely delete those rows, then the upgrade should work. Of course, if there are many such rows, it may bot be possible to clean up manually.

Average of ratings:Useful (1)
In reply to Tim Hunt

Re: Invalid context id specified context

by Steve Lawrence -

I get 112 results, all instances different.  What next?

This is starting to get somewhere, thank you again for your time and expertise.

In reply to Steve Lawrence

Re: Invalid context id specified context

by Tim Hunt -
Picture of Core developers Picture of Documentation writers Picture of Particularly helpful Moodlers Picture of Peer reviewers Picture of Plugin developers

You need to investigate some specific examples. Suppose one of the problems the last query showed is (module, instance) = (13, 123). So, get the full rows corresponding to that:

SELECT * FROM mdl_course_modules WHERE module = 13 AND instance = 123

Look at the course there, which might be something like 42 (or it may be different in each row). Anyway, then go and look at that course in your web browser (.../coures/view.php?id=42) and see if you can find the quiz there.

In reply to Tim Hunt

Re: Invalid context id specified context

by Steve Lawrence -

Okay, I've done three so far and all of them have one course that's been created by students as part of some test/training.  So we'll say for now that they are not needed, would just deleting the course(s) fix the problem? 

But now I also have some that appear to both be valid course...

 

In reply to Steve Lawrence

Re: Invalid context id specified context

by Steve Lawrence -

I have 62 unique courses from those results.  Most of which will be valid courses (unfortunately).  Looking closer for quizzes...

 

In reply to Steve Lawrence

Re: Invalid context id specified context

by Tim Hunt -
Picture of Core developers Picture of Documentation writers Picture of Particularly helpful Moodlers Picture of Peer reviewers Picture of Plugin developers

So, the dodgy data we have looks like this:

      __ course_module 2 ___
/ \
quiz course
\__ course_module 1 ___/

with duplicate course_modules, and there should only be one course_module in the middle there. So, it may not do too much harm to delete one of those. It is just working out which one to delete, and whether that causes any bad side effects.

In reply to Tim Hunt

Re: Invalid context id specified context

by Steve Lawrence -

Having a look it seems that the two courses both have the same quiz as an activity.  I can't tell you how they did it, but that's what we have.  

However they each have a different id when you go to it from the different courses.

e.g.

/mod/quiz/view.php?id=2852

/mod/quiz/view.php?id=661

Is the same quiz  (same title, same questions, same attempts) from two different courses but both have the same instance from course_modules.

This?

     __ course_module 1 --- course A
/
quiz
\__ course_module 2 --- course B

It does look like one of the rows from the two has an idnumber of NULL and the other is blank. If that helps choose the one to delete?

In reply to Steve Lawrence

Re: Invalid context id specified context

by Steve Lawrence -

Looking even closer the majority of these appear to be training courses (i.e. courses set up as training in how to set up courses) and can probably be deleted.  Others have obviously got stray quizzes that don't belong (an unrelated, and hidden, quiz on religion in a science topic for example) which can be deleted.  I'm going to work through the obvious ones first and see what we're left with.  If I need further help I'll be back. smile

In reply to Steve Lawrence

Re: Invalid context id specified context

by Tim Hunt -
Picture of Core developers Picture of Documentation writers Picture of Particularly helpful Moodlers Picture of Peer reviewers Picture of Plugin developers

There is a 'course' column in the quiz table too, so in some cases, you can just keep the course_modules row that has the matching value for course set.

Be careful doing the delete. When you delete a course, it deletes all the associated data. You don't want it to delete the quiz when you delete the 'other' course. I suggest you just delete the bad course_module rows manually.

In reply to Tim Hunt

Re: Invalid context id specified context

by Steve Lawrence -

Okay, will do, thanks.

In reply to Steve Lawrence

Re: Invalid context id specified context

by Steve Lawrence -

Let's say that someone actually wants the same quiz in two different courses - one might be, for example, a summary of a series of courses with the quizzes all brought together - which is what a couple of these seem to be - what would be the correct way to do this without breaking the upgrade routine?

In reply to Steve Lawrence

Re: Invalid context id specified context

by Tim Hunt -
Picture of Core developers Picture of Documentation writers Picture of Particularly helpful Moodlers Picture of Peer reviewers Picture of Plugin developers

This is really not supported. The only case I know where someting like this was possible is in ForumNG, where sam marshall did an amazing hack to make it appear that one forum is shared between two different courses. (We are not proposing to include that bit when we submit ForumNG for inclusion in some future Moodle version.)

To be honest, a better approach is to make a new course "Shared quizzes" which might be a Metacourse, and then enrol all the students from both separate courses in that.

In reply to Tim Hunt

Re: Invalid context id specified context

by Steve Lawrence -

Noted, thanks.  And yes, I have learned a fair bit about the scarily complicated Moodle database during this process. smile  It's also blown off a bit of dust from my SQL.

Cheers.

In reply to Steve Lawrence

Re: Invalid context id specified context

by Steve Lawrence -

Further information for anyone else following along at home...

Looking up the instance in the mdl_quiz table the course matches the second course from mdl_course_modules for every duplicate.  So I'm using that to make the assumption/decision that that is the correct course for the quiz and will delete the first instance of it.

Most bizzare.

In reply to Steve Lawrence

Re: Invalid context id specified context

by Steve Lawrence -

Update.  Cleaned up the quizzes and test upgrade went straight to 2.2 without any errors and with everything appearing to work.  Let's hope that's it now!

Thank you.

In reply to Steve Lawrence

Re: Invalid context id specified context

by Tim Hunt -
Picture of Core developers Picture of Documentation writers Picture of Particularly helpful Moodlers Picture of Peer reviewers Picture of Plugin developers

Yay! I am glad you got there. Well done for sticking with it. I hope all the arcane things you have learned about the Moodle database while going through this proves useful to you in future.