Skip to content

fix: harden DAG param validation and artifact inference#2049

Merged
yohamta0 merged 13 commits into
mainfrom
fix/optional-param-template-empty
Apr 28, 2026
Merged

fix: harden DAG param validation and artifact inference#2049
yohamta0 merged 13 commits into
mainfrom
fix/optional-param-template-empty

Conversation

@yohamta0

@yohamta0 yohamta0 commented Apr 28, 2026

Copy link
Copy Markdown
Collaborator

Summary

  • resolve omitted optional DAG params as empty values in template executor config instead of leaking literal placeholders
  • auto-enable DAG artifacts when the spec references DAG_RUN_ARTIFACTS_DIR
  • reject malformed top-level inline DAG param schema shapes instead of silently falling back to legacy param parsing

Testing

  • go test ./internal/runtime -count=1
  • go test ./internal/intg -run TestTemplateExecutor -count=1
  • go test ./internal/core/spec -count=1
  • go test ./internal/cmn/schema -count=1

Summary by CodeRabbit

  • New Features

    • Artifacts automatically enable when DAG steps reference the artifacts directory
    • Optional template parameters now gracefully resolve to empty values when omitted
  • Improvements

    • Enhanced schema validation for DAG parameter definitions
    • Improved template execution and parameter substitution handling

@coderabbitai

coderabbitai Bot commented Apr 28, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto incremental reviews are disabled on this repository.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 3ea4bad4-2d56-4ea3-badd-4edaa2b44964

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

This pull request introduces artifact auto-enablement by detecting DAG_RUN_ARTIFACTS_DIR references in DAG specifications, tightens inline JSON Schema validation for parameters, and enhances template execution by treating omitted optional parameters as empty strings during evaluation. It includes integration and unit tests across schema validation, artifact detection, and runtime parameter handling.

Changes

Cohort / File(s) Summary
Schema Validation & Tightening
internal/cmn/schema/dag.schema.json, internal/cmn/schema/dag_schema_test.go
Extended dagParamLegacyMap exclusion rules to explicitly reject inline JSON-schema-like objects where type is "object" and properties is present. Added test validating rejection of malformed params with properties as an array instead of object.
Inline JSON Schema Refactoring
internal/core/spec/dparams_inline_schema.go, internal/core/spec/dparams_inline_schema_test.go
Refactored schema detection into classifyInlineJSONSchema to capture malformed properties shapes; added malformedInlineJSONSchemaShapeError helper to report validation errors when properties is not an object. Introduced tests validating error handling for incorrectly shaped properties arrays.
Parameter Validation Integration
internal/core/spec/dparams.go
Added early validation check in buildDAGParamPlan via malformedInlineJSONSchemaShapeError to reject malformed inline schemas before processing.
Artifact Auto-Enablement Detection
internal/core/spec/dag.go, internal/core/spec/dag_test.go
Implemented recursive reflection over DAG spec to detect DAG_RUN_ARTIFACTS_DIR references using regex matching multiple env template forms (POSIX shell, template interpolation, PowerShell). Auto-enables artifacts when unspecified or when Enabled is unset and references are found. Added comprehensive tests covering multiple syntax variants and override behavior.
Template Parameter Evaluation
internal/runtime/eval.go, internal/runtime/eval_test.go
Added alternate object-evaluation path that clones user envs and injects defined DAG parameters with empty-string values when omitted. Introduced helper functions for env cloning and positional-name detection. Added test verifying undefined parameters remain as template placeholders.
Executor Config Evaluation
internal/runtime/node.go, internal/runtime/node_internal_test.go
Modified setupExecutor to conditionally use new evalObjectTreatingOmittedParamsAsEmpty for "template" type executors while preserving standard EvalObject for other types. Added test verifying template executor configs treat omitted optional parameters as empty strings.
Integration Testing
internal/intg/template_test.go
Added CLI-driven integration tests for template execution: artifact output with ${DAG_RUN_ARTIFACTS_DIR} references, optional parameter resolution to empty values, and conditional rendering behavior.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

  • feat: add schema-backed DAG param forms #2039: Refines inline JSON Schema handling for DAG parameters by tightening rejection logic for malformed params.properties shapes and adding validation in param plan building, directly complementing schema sanitization and parameter exposure work.
  • feat: add DAG run artifacts support #1998: Overlaps with artifact-related changes across spec building (buildArtifacts), runtime evaluation, and integration testing; shared focus on DAG run artifacts feature and DAG_RUN_ARTIFACTS_DIR handling.
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 25.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main changes: hardening DAG parameter validation (rejecting malformed inline schemas) and artifact inference (auto-enabling based on environment variable references).
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/optional-param-template-empty

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (1)
internal/core/spec/dag_params_inline_schema_test.go (1)

75-90: Add path assertion parity in the skip-validation variant.

To keep the contract equally strict, also assert that the error is attributed to params (like the non-skip variant).

Suggested test tweak
 	_, err := LoadYAML(context.Background(), yaml, SkipSchemaValidation(), WithoutEval())
 	require.Error(t, err)
+	assert.Contains(t, err.Error(), "params")
 	assert.Contains(t, err.Error(), "properties must be an object")
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@internal/core/spec/dag_params_inline_schema_test.go` around lines 75 - 90,
The test
TestBuildInlineSchemaParamPlan_SkipSchemaValidationStillRejectsPropertiesArrayShape
currently only asserts the error message; update it to also assert the error
path matches the params field like the non-skip variant by inspecting the
returned error from LoadYAML (called with SkipSchemaValidation() and
WithoutEval()) and asserting the error's path/field is "params" (or contains
"params") so the test enforces the same path attribution as the non-skip case.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@internal/core/spec/dag.go`:
- Around line 870-872: The current reflect.String case uses a raw substring
check against dagRunArtifactsDirEnvKey which is too permissive; update the
reflect.String branch (the switch handling value kinds) to only treat strings as
env-var references when they match actual env-var reference forms (e.g.
$DAG_RUN_ARTIFACTS_DIR, ${DAG_RUN_ARTIFACTS_DIR}, or
env("DAG_RUN_ARTIFACTS_DIR")), not any string containing the token; implement
this by replacing strings.Contains(v.String(), dagRunArtifactsDirEnvKey) with a
pattern check (simple regex or explicit prefix/suffix checks) that verifies the
exact reference forms and use dagRunArtifactsDirEnvKey in the pattern. Ensure
other branches (Array/Slice) keep existing behavior.

---

Nitpick comments:
In `@internal/core/spec/dag_params_inline_schema_test.go`:
- Around line 75-90: The test
TestBuildInlineSchemaParamPlan_SkipSchemaValidationStillRejectsPropertiesArrayShape
currently only asserts the error message; update it to also assert the error
path matches the params field like the non-skip variant by inspecting the
returned error from LoadYAML (called with SkipSchemaValidation() and
WithoutEval()) and asserting the error's path/field is "params" (or contains
"params") so the test enforces the same path attribution as the non-skip case.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 865ac54a-1981-41cc-ba5a-5867bdd2cbcf

📥 Commits

Reviewing files that changed from the base of the PR and between 9d0668c and 07607df.

📒 Files selected for processing (10)
  • internal/cmn/schema/dag.schema.json
  • internal/cmn/schema/dag_schema_test.go
  • internal/core/spec/dag.go
  • internal/core/spec/dag_params.go
  • internal/core/spec/dag_params_inline_schema.go
  • internal/core/spec/dag_params_inline_schema_test.go
  • internal/core/spec/dag_test.go
  • internal/intg/template_test.go
  • internal/runtime/eval.go
  • internal/runtime/eval_test.go

Comment thread internal/core/spec/dag.go
@yohamta0

Copy link
Copy Markdown
Collaborator Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Apr 28, 2026

Copy link
Copy Markdown
✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
internal/core/spec/dag.go (1)

882-904: Add a default branch for code clarity, though not currently required by exhaustive lint.

The switch at line 882 omits a default case, and while the exhaustive linter does not currently flag this (despite covering only 5 of 27 possible reflect.Kind values), adding default: return false would make the intent explicit that other kinds are unhandled.

Suggested fix
 switch v.Kind() {
 case reflect.String:
 	return referencesArtifactsEnvVar(v.String())
 case reflect.Array, reflect.Slice:
 	for i := 0; i < v.Len(); i++ {
 		if valueReferencesRunArtifactsDir(v.Index(i)) {
 			return true
 		}
 	}
 case reflect.Map:
 	iter := v.MapRange()
 	for iter.Next() {
 		if valueReferencesRunArtifactsDir(iter.Key()) || valueReferencesRunArtifactsDir(iter.Value()) {
 			return true
 		}
 	}
 case reflect.Struct:
 	for _, field := range v.Fields() {
 		if valueReferencesRunArtifactsDir(field) {
 			return true
 		}
 	}
+default:
+	return false
 }
 
 return false
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@internal/core/spec/dag.go` around lines 882 - 904, The switch inside
valueReferencesRunArtifactsDir currently handles String, Array/Slice, Map, and
Struct kinds but lacks an explicit default; add a default case to the switch (in
the valueReferencesRunArtifactsDir function) that returns false to make the
intent explicit for all other reflect.Kind values and satisfy clarity/linting
expectations.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@internal/core/spec/dag.go`:
- Around line 882-904: The switch inside valueReferencesRunArtifactsDir
currently handles String, Array/Slice, Map, and Struct kinds but lacks an
explicit default; add a default case to the switch (in the
valueReferencesRunArtifactsDir function) that returns false to make the intent
explicit for all other reflect.Kind values and satisfy clarity/linting
expectations.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 665505d1-ed05-4a2c-afe4-6736a239fddd

📥 Commits

Reviewing files that changed from the base of the PR and between 07607df and 1424298.

📒 Files selected for processing (4)
  • internal/core/spec/dag.go
  • internal/core/spec/dag_params_inline_schema_test.go
  • internal/core/spec/dag_test.go
  • internal/runtime/eval.go
🚧 Files skipped from review as they are similar to previous changes (3)
  • internal/core/spec/dag_params_inline_schema_test.go
  • internal/runtime/eval.go
  • internal/core/spec/dag_test.go

@yohamta0

Copy link
Copy Markdown
Collaborator Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Apr 28, 2026

Copy link
Copy Markdown
✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@yohamta0

Copy link
Copy Markdown
Collaborator Author

@coderabbitai full review

@coderabbitai

coderabbitai Bot commented Apr 28, 2026

Copy link
Copy Markdown
✅ Actions performed

Full review triggered.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@internal/core/spec/dag.go`:
- Around line 898-903: The code uses the non-existent method v.Fields() (inside
the reflect.Struct case) which causes a compile error; replace that iteration
with the standard reflect APIs by looping from i := 0; i < v.NumField(); i++ and
calling v.Field(i) for each field, then call valueReferencesRunArtifactsDir on
each retrieved field value (preserving the existing early-return behavior);
update the case block where v.Fields() is referenced to use NumField() and
Field(i).

In `@internal/core/spec/dparams_inline_schema.go`:
- Around line 18-64: The classifier fails to surface a present-but-nil
"properties" key (e.g., params: {type: "object", properties: null}) because
malformedProperties can be nil; update inlineJSONSchemaClassification to include
a propertiesPresent bool, set propertiesPresent=true when m["properties"] exists
(even if nil) inside classifyInlineJSONSchema, and then change
malformedInlineJSONSchemaShapeError to return a validation error when
classification.propertiesPresent is true but classification.valid is false (or
when malformedProperties is non-nil), ensuring present-but-malformed (including
null) properties produce the error; reference inlineJSONSchemaClassification,
classifyInlineJSONSchema, and malformedInlineJSONSchemaShapeError.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 6182a8a6-fb1e-4457-99ef-15e56741a13e

📥 Commits

Reviewing files that changed from the base of the PR and between 9d0668c and 1b95367.

📒 Files selected for processing (16)
  • internal/cmn/schema/dag.schema.json
  • internal/cmn/schema/dag_schema_test.go
  • internal/core/spec/dag.go
  • internal/core/spec/dag_test.go
  • internal/core/spec/dparams.go
  • internal/core/spec/dparams_external_schema.go
  • internal/core/spec/dparams_inline.go
  • internal/core/spec/dparams_inline_schema.go
  • internal/core/spec/dparams_inline_schema_test.go
  • internal/core/spec/dparams_runtime.go
  • internal/core/spec/dparams_test.go
  • internal/intg/template_test.go
  • internal/runtime/eval.go
  • internal/runtime/eval_test.go
  • internal/runtime/node.go
  • internal/runtime/node_internal_test.go

Comment thread internal/core/spec/dag.go
Comment on lines +898 to +903
case reflect.Struct:
for _, field := range v.Fields() {
if valueReferencesRunArtifactsDir(field) {
return true
}
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

cd /tmp && find . -type f -name "dag.go" -path "*/internal/core/spec/*" 2>/dev/null | head -5

Repository: dagucloud/dagu

Length of output: 40


🏁 Script executed:

# Let's first list the repository structure to locate the file
git ls-files | grep -E "dag\.go" | head -10

Repository: dagucloud/dagu

Length of output: 211


🏁 Script executed:

# Check the specific file and lines mentioned
sed -n '890,910p' internal/core/spec/dag.go

Repository: dagucloud/dagu

Length of output: 499


🏁 Script executed:

sed -n '870,920p' internal/core/spec/dag.go

Repository: dagucloud/dagu

Length of output: 1137


🏁 Script executed:

# Check if there are any type aliases or method receivers that might add Fields() to reflect.Value
rg "func.*Fields" internal/core/spec/dag.go

Repository: dagucloud/dagu

Length of output: 40


🏁 Script executed:

# Check the Go version and see if there's any build output showing compilation errors
cat go.mod | head -20

Repository: dagucloud/dagu

Length of output: 655


🏁 Script executed:

# Try to find if Fields() is defined anywhere as a method on reflect.Value
rg "func \(.*reflect\.Value.*\).*Fields" --type go

Repository: dagucloud/dagu

Length of output: 40


🏁 Script executed:

# Double-check Go reflect package documentation by looking at reflect usage elsewhere
rg "\.NumField\(\)" internal/core/spec/dag.go | head -5

Repository: dagucloud/dagu

Length of output: 40


🏁 Script executed:

# Verify that this code path is actually being used and not a dead code path
rg "valueReferencesRunArtifactsDir" internal/core/spec/dag.go

Repository: dagucloud/dagu

Length of output: 373


reflect.Value.Fields() does not exist in Go's standard library and will cause a compilation error.

Replace v.Fields() with the standard API using NumField() and Field(i):

Suggested fix
 case reflect.Struct:
-	for _, field := range v.Fields() {
-		if valueReferencesRunArtifactsDir(field) {
-			return true
-		}
-	}
+	for i := 0; i < v.NumField(); i++ {
+		if valueReferencesRunArtifactsDir(v.Field(i)) {
+			return true
+		}
+	}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@internal/core/spec/dag.go` around lines 898 - 903, The code uses the
non-existent method v.Fields() (inside the reflect.Struct case) which causes a
compile error; replace that iteration with the standard reflect APIs by looping
from i := 0; i < v.NumField(); i++ and calling v.Field(i) for each field, then
call valueReferencesRunArtifactsDir on each retrieved field value (preserving
the existing early-return behavior); update the case block where v.Fields() is
referenced to use NumField() and Field(i).

Comment on lines +18 to +64
type inlineJSONSchemaClassification struct {
valid bool
malformedProperties any
}

// isInlineJSONSchema returns true when params is a top-level JSON Schema object
// using the canonical object form. This keeps legacy params maps compatible.
func isInlineJSONSchema(input any) bool {
return classifyInlineJSONSchema(input).valid
}

func classifyInlineJSONSchema(input any) inlineJSONSchemaClassification {
m, ok := input.(map[string]any)
if !ok {
return false
return inlineJSONSchemaClassification{}
}
// External schema format takes precedence.
if _, ok := extractParamsSchemaDeclaration(input); ok {
return false
return inlineJSONSchemaClassification{}
}
typeName, ok := m["type"].(string)
if !ok || strings.TrimSpace(typeName) != "object" {
return false
return inlineJSONSchemaClassification{}
}
props, ok := m["properties"]
if !ok {
return false
return inlineJSONSchemaClassification{}
}
_, ok = props.(map[string]any)
return ok

if _, ok := props.(map[string]any); ok {
return inlineJSONSchemaClassification{valid: true}
}

return inlineJSONSchemaClassification{malformedProperties: props}
}

func malformedInlineJSONSchemaShapeError(input any) error {
classification := classifyInlineJSONSchema(input)
if classification.malformedProperties == nil {
return nil
}

return core.NewValidationError(
"params",
classification.malformedProperties,
fmt.Errorf("inline JSON Schema properties must be an object keyed by parameter name"),
)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Track malformed properties presence separately.

malformedInlineJSONSchemaShapeError only fires when malformedProperties is non-nil, so params: { type: object, properties: null } still falls through to legacy parsing when schema validation is skipped. That leaves a malformed inline-schema shape unblocked.

🛠️ Suggested fix
 type inlineJSONSchemaClassification struct {
-	valid               bool
-	malformedProperties any
+	valid                    bool
+	malformedProperties      bool
+	malformedPropertiesValue any
 }
@@
 	if _, ok := props.(map[string]any); ok {
 		return inlineJSONSchemaClassification{valid: true}
 	}
 
-	return inlineJSONSchemaClassification{malformedProperties: props}
+	return inlineJSONSchemaClassification{
+		malformedProperties:      true,
+		malformedPropertiesValue: props,
+	}
 }
@@
-	if classification.malformedProperties == nil {
+	if !classification.malformedProperties {
 		return nil
 	}
@@
-		classification.malformedProperties,
+		classification.malformedPropertiesValue,
 		fmt.Errorf("inline JSON Schema properties must be an object keyed by parameter name"),
 	)
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
type inlineJSONSchemaClassification struct {
valid bool
malformedProperties any
}
// isInlineJSONSchema returns true when params is a top-level JSON Schema object
// using the canonical object form. This keeps legacy params maps compatible.
func isInlineJSONSchema(input any) bool {
return classifyInlineJSONSchema(input).valid
}
func classifyInlineJSONSchema(input any) inlineJSONSchemaClassification {
m, ok := input.(map[string]any)
if !ok {
return false
return inlineJSONSchemaClassification{}
}
// External schema format takes precedence.
if _, ok := extractParamsSchemaDeclaration(input); ok {
return false
return inlineJSONSchemaClassification{}
}
typeName, ok := m["type"].(string)
if !ok || strings.TrimSpace(typeName) != "object" {
return false
return inlineJSONSchemaClassification{}
}
props, ok := m["properties"]
if !ok {
return false
return inlineJSONSchemaClassification{}
}
_, ok = props.(map[string]any)
return ok
if _, ok := props.(map[string]any); ok {
return inlineJSONSchemaClassification{valid: true}
}
return inlineJSONSchemaClassification{malformedProperties: props}
}
func malformedInlineJSONSchemaShapeError(input any) error {
classification := classifyInlineJSONSchema(input)
if classification.malformedProperties == nil {
return nil
}
return core.NewValidationError(
"params",
classification.malformedProperties,
fmt.Errorf("inline JSON Schema properties must be an object keyed by parameter name"),
)
type inlineJSONSchemaClassification struct {
valid bool
malformedProperties bool
malformedPropertiesValue any
}
// isInlineJSONSchema returns true when params is a top-level JSON Schema object
// using the canonical object form. This keeps legacy params maps compatible.
func isInlineJSONSchema(input any) bool {
return classifyInlineJSONSchema(input).valid
}
func classifyInlineJSONSchema(input any) inlineJSONSchemaClassification {
m, ok := input.(map[string]any)
if !ok {
return inlineJSONSchemaClassification{}
}
// External schema format takes precedence.
if _, ok := extractParamsSchemaDeclaration(input); ok {
return inlineJSONSchemaClassification{}
}
typeName, ok := m["type"].(string)
if !ok || strings.TrimSpace(typeName) != "object" {
return inlineJSONSchemaClassification{}
}
props, ok := m["properties"]
if !ok {
return inlineJSONSchemaClassification{}
}
if _, ok := props.(map[string]any); ok {
return inlineJSONSchemaClassification{valid: true}
}
return inlineJSONSchemaClassification{
malformedProperties: true,
malformedPropertiesValue: props,
}
}
func malformedInlineJSONSchemaShapeError(input any) error {
classification := classifyInlineJSONSchema(input)
if !classification.malformedProperties {
return nil
}
return core.NewValidationError(
"params",
classification.malformedPropertiesValue,
fmt.Errorf("inline JSON Schema properties must be an object keyed by parameter name"),
)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@internal/core/spec/dparams_inline_schema.go` around lines 18 - 64, The
classifier fails to surface a present-but-nil "properties" key (e.g., params:
{type: "object", properties: null}) because malformedProperties can be nil;
update inlineJSONSchemaClassification to include a propertiesPresent bool, set
propertiesPresent=true when m["properties"] exists (even if nil) inside
classifyInlineJSONSchema, and then change malformedInlineJSONSchemaShapeError to
return a validation error when classification.propertiesPresent is true but
classification.valid is false (or when malformedProperties is non-nil), ensuring
present-but-malformed (including null) properties produce the error; reference
inlineJSONSchemaClassification, classifyInlineJSONSchema, and
malformedInlineJSONSchemaShapeError.

@yohamta0 yohamta0 merged commit c1ea23c into main Apr 28, 2026
10 checks passed
@yohamta0 yohamta0 deleted the fix/optional-param-template-empty branch April 28, 2026 22:25
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant