Dynamic Defaults not working if nested in a group within a Repeat

1. What is the issue? Please be detailed.
My context is that I have several groups that I want to display using the appearance field-list in Collect that are all within a repeat. Several of the groups are data that change infrequently so I want to use the last-saved as defaults for all of the questions in those groups, however, they aren't working. I've followed the convention outlined in the docs and can confirm it works for questions within the repeat, but not for questions nested in a group within a repeat.

I'm not sure if this is a bug or I'm doing it wrong, but this is a showstopper for several forms/workflows that I'd like to use immediately.

2. What steps can we take to reproduce this issue?
Make a question within a group that is within a repeat. Try to make a dynamic default by putting something like this in the default column:

This works for the question w/in the repeat, but NOT for the question in group in a repeat.

if(position(..) >= 1,
   ${r_1}[position() = position(current()/..) - 1]/s_brick_type,
   ''
)```

This doesn't work either for the question in a group w/in a repeat.

"if(position(..) >= 1,
   ${r_1}[position() = position(current()/..) - 1]/g_people_positions/s_brick_type2,
   ''
)"

3. What have you tried to fix the issue?
I encountered this before but have simplified my example form to be much simpler w only 9 lines.

4. Upload any forms or screenshots you can share publicly below.

Default in repeat and group in repeat.xlsx (106.7 KB)

Are y'all ready to go down the inception train?

2Wl
All of these dynamic defaults are using the previous repeat instance answer as the default, which is incredibly useful when you have many repeats with only slightly different answers.

Layer 1

Dynamic Default for a question s_brick_type_works2 inside a repeat group called r_1

${r_1}[position() = position(current()/..) - 1]/s_brick_type_works2

Layer 2

Dynamic Default for a question s_brick_type4 inside a group g_people inside a repeat r_1

${r_1}[position() = position(current()/../..) - 1]/g_people/s_brick_type4

Layer 3

Dynamic Default for a question s_dreams3 inside a group g_inception inside a group g_people inside a repeat r_1

${r_1}[position() = position(current()/../../..) - 1]/g_people/g_inception/s_dreams3

or

 indexed-repeat(${s_dreams4}, ${r_1}, position(current()/../../..) - 1)

Reference Form:

Default w_in group nested in repeat.xlsx (108.7 KB)

AI Commentary

I spent a good hr+ messing around with Kappa trying to get to the bottom of this issue without luck. Eventually I came up with a detailed prompt given info from this initial conversation. I then tried this prompt in Kappa, ChatGPT, Gemini 3. You can see that Gemini 3 got straight to the root of the issue, whereas the others never identified that and lead me on a wild goose chase. I did try using the suggested helper method ChatGPT/Gemini 3 suggested but I couldn't get it working.

Original Prompt

I'm trying to diagnose the source of what seems like a bug in using ODK Collect/designing an XLSForm. I'm trying to use a dynamic default inside a group nested inside a repeat. Can you give me suggestions as to how to proceed from here. Do I need to inspect the JavaRosa Codebase?Do I need to try something else in my XLSForm?

Here is an original post about the issue: Dynamic Defaults not working if nested in a group within a Repeat

Here is the public codebase for ODK: https://github.com/getodk I'm using ODK Collect. https://github.com/getodk/collect

Here is a response from another AI source familiar with ODK and XLSForms.

I’m sorry, but the knowledge sources you’ve provided don’t include JavaRosa source code, so I can’t actually “look at the JavaRosa codebase” or point to a specific line or function that’s causing this. I can only infer behavior from documentation and forum discussions.
Here is what is in the sources and how it relates to your issue:

  1. Dynamic defaults in repeats are implemented via with events
    Dynamic defaults (including “previous repeat” defaults) are compiled by pyxform into XForms actions that fire on odk-new-repeat (and odk-instance-first-load), with the ref pointing at the target node and the value holding your XPath expression. [Dynamic defaults repeats; Entities from repeats example]
  2. The “previous repeat” pattern you’re using is exactly the documented one
    The docs show:
  3. ${tree}[position() = position(current()/..) - 1]/species
    as the correct default expression to pull a value from the previous repeat instance. [Dynamic defaults repeats]
    Your working question (direct child of the repeat) follows this pattern; your group nested questions also follow it, just with /g_people/... added.
  4. There are explicit reports that this fails for group nested questions but works for direct children
    Two forum threads describe almost exactly your situation: dynamic defaults based on the previous repeat value working for a question directly under the repeat, but not working for questions inside a group within the repeat, even when using the documented pattern. [Dynamic default inside group in repeat; Defaults not working group-in-repeat]
    In those discussions:
    o The expressions are structurally the same as yours.
    o No alternative XPath variant is given that restores correct behavior.
    o The behavior is treated as a limitation/bug rather than a form author typo.
  5. Other evidence that setvalue/event handling in repeats is delicate
    o There are discussions about setvalue / trigger behavior in repeats and Enketo vs Collect that show how sensitive repeat context and current()/position() handling are. [Incorrect setvalue in repeats; Error when using trigger within repeat groups]
    o Dynamic defaults in repeats are known to be evaluated specifically on odk-new-repeat, not continuously, which constrains when previous values are visible. [Dynamic defaults repeats]
    Putting this together:
    • The spec-level behavior is clear (dynamic defaults from previous repeat should work for any descendant as long as the XPath is correct).
    • The observed behavior from users (and from your sample form) is:
    o Works for direct children of the repeat.
    o Does not work for questions inside a nested group under the repeat, even with correct XPath.
    • The sources do not include JavaRosa code or a JavaRosa issue explicitly confirming “setvalue doesn’t reach descendants in this scenario,” so I cannot definitively attribute it to a specific implementation bug in JavaRosa.
    All I can say, grounded in these materials, is:
    The mismatch between the spec/docs and what you see in Collect, combined with multiple user reports, strongly suggests a limitation or bug in how JavaRosa applies the dynamic default for descendant nodes inside a group within a repeat, but the knowledge sources here do not contain the JavaRosa code needed to confirm where or how that happens.
    If you want to go further at the code level, the next step would be:
    • File (or update) an issue on the JavaRosa / Collect trackers, attaching your minimal XLSForm that demonstrates:
    o one working default (direct child of repeat), and
    o one failing default (inside group in same repeat),
    • and have someone with access to the JavaRosa codebase trace how the generated is being evaluated for those two cases.
Kappa Response

Based on the sources you provided (and the ones the retriever added), what you’re seeing does look like a real limitation/bug, not a mistake in your XLSForm.

What we know from the docs/sources

  1. How dynamic defaults in repeats are supposed to work
  • Dynamic defaults in repeats are implemented via setvalue actions that fire on odk-instance-first-load and odk-new-repeat. [Dynamic defaults in repeats]

  • The documented pattern for “use previous repeat’s value” is exactly what you’re using, e.g.:

    ${tree}[position() = position(current()/..) - 1]/species
    

    [Dynamic defaults in repeats]

  1. Your case (group nested inside repeat) is a known problem
  • There are two threads that match your situation very closely:

    • Dynamic default inside a group within a repeat: user can get a previous‑repeat default to work for a question that is a direct child of the repeat, but not for a question inside a group in that repeat. [Dynamic default inside group in repeat]
    • Dynamic defaults not working if nested in a group within a repeat: same pattern, same symptoms. [Defaults not working group-in-repeat]
  • In those discussions, the expressions are structurally correct, and the behavior is treated as a limitation/bug rather than user error. No working alternative XPath is provided.

  1. setvalue/trigger + repeats are already known to be fragile
  • There are separate reports where setvalue/trigger behave differently or incorrectly in repeats (especially under Enketo), which confirms that repeat context + current()/position() handling are a delicate area. [Incorrect setvalue in repeats]

Given all of that, and the fact that the same expression works for a direct child of the repeat but fails for a grouped descendant, the best evidence we have is:

This is very likely a JavaRosa/Collect limitation or bug in how the setvalue for dynamic defaults is applied to nodes inside groups within a repeat.

The knowledge sources here don’t include JavaRosa source code, so I can’t point to a specific line or function.


How to proceed (practically)

1. Create / keep a minimal repro XLSForm

You already have a very small form (9 lines in the last thread). That’s exactly what maintainers will need:

  • One question that works (direct child of the repeat).
  • One question that fails (inside a group in the same repeat).
  • Both using the same “previous repeat” default pattern.

2. Inspect the generated XML once

Even without reading Java, it is useful to:

  1. Convert your XLSForm with XLSForm Online.
  2. Open the generated XML and look for the <setvalue> created for the dynamic default.

You should see something like:

<setvalue
    event="odk-instance-first-load odk-new-repeat"
    ref="/data/r_1/s_brick_type"
    value=" /data/r_1[position() = position(current()/..) - 1]/s_brick_type"/>

and a similar one for the grouped question. If both actions look structurally parallel (only the ref/path differ) but only the direct-child one works in Collect, that strongly supports “implementation bug” rather than “wrong XPath”.

3. File issues (this is more productive than hand‑reading JavaRosa yourself)

Given what’s in the sources, your next concrete step should be to open issues with a minimal repro:

Include:

  • The XLSForm (minimal repro).
  • The generated XML snippet with the relevant <setvalue>s.
  • Exact behavior: “works for /repeat/q1, fails for /repeat/group/q2 in Collect version X”.

That will let someone who does actively work in the JavaRosa codebase trace how setvalue is evaluated for those two nodes.

4. Short‑term workarounds in your form

Based on the docs and forum posts, the following are your realistic options today:

  1. Move the dynamic‑default question out of the inner group

    • Keep it as a direct child of the repeat (where it works).
    • If you need “visual grouping”, you can sometimes fake it with notes/labels or by reordering questions, rather than an actual begin group / end group.
  2. Compute once outside the group, reference inside

    • Put a calculate that gets the “previous repeat” value as a direct child of the repeat (where dynamic defaults are known to work).
    • Inside the group, refer to that calculate via calculation + trigger to get a dynamic default from form data, as described in the docs. [Defaults from form data]
    • This is a bit more complex, and the sources don’t explicitly confirm that this pattern does work for grouped descendants in your exact scenario, so you’ll need to test it.

If even these patterns fail inside the group, that’s important data to attach to the GitHub issue.


Do you need to read JavaRosa code?

You can, but based on the available information:

  • The more impactful next step is to file a well‑documented issue with your minimal form and observed behavior.
  • Once that exists, JavaRosa/Collect maintainers (who know the internals and test harnesses) can pinpoint and fix the underlying problem.

So: you don’t need to dive into JavaRosa first; structuring and reporting your repro is the most effective immediate move.

ChatGPT Response

Short version first, no sugar-coating:
you’re almost certainly running into a real JavaRosa / Collect edge-case bug or limitation, not an XLSForm mistake. You can keep poking XLSForm, but you’re unlikely to “XPath your way out of it.”

Now the longer, useful version.

What you’ve already established (correctly)
You’ve done the right forensic work already.

Dynamic defaults in repeats are implemented as <setvalue> actions fired on odk-new-repeat.
Your XPath pattern is the documented one and demonstrably works for direct children of the repeat.
The same logical XPath fails when the target node lives inside a group under the repeat.
Multiple independent reports confirm the same pattern. That’s the smoking gun.

That combination strongly points to implementation behavior, not form author error.

What’s probably going wrong under the hood (working theory)
JavaRosa doesn’t evaluate <setvalue> in a purely “spec ideal” way. It has to:

  1. Create a new repeat instance.
  2. Fire odk-new-repeat.
  3. Resolve the ref of each <setvalue>.
  4. Apply the value into the instance tree.

The failure mode you’re seeing suggests that when the target node is a descendant inside a group, one of these happens:

• The node doesn’t yet exist at the moment odk-new-repeat fires.
• The evaluation context for current() / position() is subtly different once you cross a group boundary.
• The engine resolves refs relative to the repeat instance root but doesn’t correctly descend into groups for setvalue during that event.

This would explain all observed behavior:
– Direct children exist → value applied.
– Group descendants not yet instantiated → value silently dropped.

That’s consistent with JavaRosa’s long history of “order of construction matters” bugs around repeats, groups, and events.

Do you need to inspect the JavaRosa codebase?
Only if you want to prove the bug or help fix it. You don’t need to in order to move forward.

If you do go there, here’s where to look so you don’t drown:

• JavaRosa: handling of odk-new-repeat and SetValueAction
• How instance nodes are created for groups inside repeats
• Timing of instance tree creation vs action firing

That’s non-trivial Java, not a quick skim. Expect a few evenings, not 20 minutes.

What you should try in XLSForm (practical escape hatches)
These are not pretty, but they work around JavaRosa’s behavior.

  1. Move the default target out of the group
    If the field can logically live as a direct child of the repeat, do that and reference it from inside the group. This avoids the bug entirely.

  2. Use an explicit calculate instead of a default
    Sometimes moving the logic to a calculate that depends on position() and the previous repeat works because calculates are re-evaluated after the instance exists. It’s not guaranteed, but worth testing.

  3. Use a trigger + setvalue pattern after creation
    Instead of relying solely on odk-new-repeat, use a trigger question that fires after the repeat instance is fully built, then applies setvalue to the group child. Ugly, but often effective.

  4. Duplicate the value at the repeat level
    Set the default at the repeat level (where it works), then copy it into the group field with a calculate. Redundant data, but reliable.

What not to waste time on
• Tweaking XPath syntax endlessly
• Assuming Enketo behavior implies Collect behavior
• Expecting pyxform changes to fix this

The problem is downstream of XLSForm compilation.

What is worth doing for the ecosystem
File or update an issue, exactly as you described:

Minimal XLSForm
One working case (direct child)
One broken case (group descendant)
Exact Collect version

That gives JavaRosa maintainers something concrete to step through in a debugger. Without that, this kind of bug lives forever in forum lore.

Bottom line
You’re not missing a clever XPath trick. You’ve found a real corner where theory and implementation part ways. Treat it like a physics experiment where the apparatus has friction: design around it, document it, and—if you’re feeling civic-minded—help get it fixed upstream.

Gemini 3 Response

You do not need to inspect the JavaRosa codebase yourself, nor do you need to wait for a patch to the ODK Collect app to fix this.

Based on the ODK Forum threads and known behavior of XForms/XPath, this is a context issue (not necessarily a bug, but a strict adherence to XPath rules that becomes confusing).

When you place a question inside a Group, the "context" shifts.

  • Direct Child: current()/.. refers to the Repeat.
  • Nested in Group: current()/.. refers to the Group, and current()/../.. refers to the Repeat.

This breaks the standard "previous value" formula because position(current()/..) is calculating the position of the group (which is always 1) rather than the repeat (which increments 1, 2, 3...).

Here are three solutions to fix your XLSForm, ranked from easiest to most robust.

Solution 1: Adjust the Path (The "Quick Fix")

You need to point the position calculator up one more level to find the repeat, and you likely need to include the group in your source path.

Change your default calculation from:

${repeat_name}[position() = position(current()/..) - 1]/question_name

To:

${repeat_name}[position() = position(current()/../..) - 1]/group_name/question_name

  • current()/../..: This goes up two levels (Question -> Group -> Repeat) to get the correct repeat index.
  • /group_name/: You must include the group in the path to the previous value, because the previous value is also buried inside that group.

Solution 2: The "Helper Variable" (Recommended/Most Robust)

Complex XPath expressions inside groups can be fragile (as you've seen). The most stable workaround is to calculate the position outside the group first.

  1. Create a calculate question strictly inside the Repeat but outside the Group.
  • Name: calc_pos
  • Calculation: position(..)
  1. Inside your Group, use this ${calc_pos} variable in your default logic.
  • Default:
if(${calc_pos} > 1, ${repeat_name}[position() = ${calc_pos} - 1]/group_name/question_name, '')

This isolates the "position finding" logic to a place where it is guaranteed to work (direct child of repeat), preventing the group context from breaking it.


Solution 3: Use indexed-repeat()

If the relative paths (Solution 1) are still failing or throwing errors, switch to the absolute reference function indexed-repeat(). This is often safer for complex nesting.

Formula:

indexed-repeat(${question_name}, ${repeat_name}, position(current()/../..) - 1)

Note: You may still need the "Helper Variable" from Solution 2 to replace position(current()/../..) if the position function continues to return "1".

Summary Diagnosis

  • Do you need to check JavaRosa code? No. The code is likely doing exactly what XPath spec says (checking the parent's position), but "Parent" has changed from "Repeat" to "Group".
  • Why it fails: position(current()/..) inside a group evaluates to "Position of this group inside this repeat", which is always 1.
  • The Fix: Use position(current()/../..) or a helper variable outside the group.

Would you like me to write out the specific XLSForm syntax for Solution 2 (the helper variable approach) if you paste your current variable names?