Skip to content

Conversation

@PrayagCodes
Copy link

@PrayagCodes PrayagCodes commented Nov 24, 2025

Summary

This PR fixes two critical bugs in the mkdir filesystem operation:

  1. Root directory protection: Attempting to create directories in the root directory now returns 403 Forbidden instead of 500 Internal Server Error
  2. create_missing_parents flag: Fixed the flag to actually create intermediate directories instead of failing with 422 Unprocessable Entity

Problem

Issue #1: Incorrect Error Status for Root Directory Operations

When users attempt to create directories in the root directory (e.g., puter.fs.mkdir('/foo')), the system returns a 500 Internal Server Error. This is problematic because:

  • 500 status codes indicate unexpected server failures
  • Root directory is intentionally read-only by design
  • This misleads API consumers and breaks proper error handling
  • Client applications cannot distinguish between policy violations and actual server errors

Issue #2: create_missing_parents Flag Not Working

The create_missing_parents flag was returning 422 dest_does_not_exist errors instead of creating intermediate directories due to:

  • SDK splitting paths into parent + basename before sending to API
  • SDK not supporting snake_case parameter names
  • Backend always calling _get_existing_parent regardless of flag value

Solution

Changes Made

1. Backend - API Error Definition (src/backend/src/api/APIError.js)

  • Added new error code cannot_create_in_root with 403 status
  • Clear error message: "Directories cannot be created in the root directory."

2. Backend - Root Directory Validation (src/backend/src/filesystem/hl_operations/hl_mkdir.js)

  • Added validation check to prevent root directory operations
  • Enhanced check to prevent create_missing_parents from creating non-user directories at root
  • Allows creation inside existing user directories while blocking arbitrary root-level directories
  • Added conditional parent creation based on create_missing_parents flag

3. SDK - Path Handling Fix (src/puter-js/src/modules/FileSystem/operations/mkdir.js)

  • Changed from sending parent + basename to sending full path
  • Added support for snake_case create_missing_parents parameter
  • Made SDK consistent with move and copy operations

Testing

All test cases verified and passing:

Test Case Input Expected Result
Direct root creation mkdir('/testroot') 403 Forbidden Pass
Root with flag mkdir('/testroot2', {create_missing_parents: true}) 403 Forbidden Pass
Nested root creation mkdir('/testroot3/nested', {create_missing_parents: true}) 403 Forbidden Pass
Valid directory mkdir('/username/Videos/testdir') Success Pass
Valid nested mkdir('/username/Videos/testdir/nested') Success Pass
Valid with parents flag mkdir('/username/Videos/testdir2/nested', {create_missing_parents: true}) Success (creates both) Pass

Technical Details

Why 403 Instead of 422?

  • 403 Forbidden more accurately represents a permission/policy restriction
  • Improves API consistency with standard HTTP semantics
  • Aligns with REST API best practices

Backward Compatibility

  • Backend still accepts the old parent parameter for batch operations (file uploads)
  • Existing code continues to work without modifications

Implementation Pattern

  • Mirrors the approach used in hl_write.js for consistency
  • Uses existing FSNodeContext.isRoot property for reliable root detection
  • Validation occurs early, before any database operations

Checklist

  • Error code added to APIError.js with status 403
  • Root directory check added to hl_mkdir.js
  • Enhanced check prevents create_missing_parents from bypassing protection
  • SDK sends full path instead of parent+basename
  • SDK accepts both camelCase and snake_case parameters
  • Backend conditionally creates or validates parents based on flag
  • All 6 test cases pass as expected
  • No linter errors introduced
  • Manual testing completed successfully
  • Backward compatibility verified

Related Files

  • src/backend/src/api/APIError.js - Error code definitions
  • src/backend/src/filesystem/hl_operations/hl_mkdir.js - High-level mkdir operation
  • src/puter-js/src/modules/FileSystem/operations/mkdir.js - SDK mkdir implementation
  • src/backend/src/filesystem/hl_operations/hl_write.js - Reference implementation
  • src/backend/src/filesystem/FSNodeContext.js - isRoot property definition

Fixes: Root directory mkdir operations returning 500 instead of 403
Fixes: create_missing_parents flag not creating intermediate directories

…rents flag

This commit addresses two related issues with the mkdir operation:

1. Root directory protection (403 Forbidden):
   - Added 'cannot_create_in_root' error code to APIError.js
   - Added validation in hl_mkdir.js to prevent creating directories in root
   - Enhanced check to prevent create_missing_parents from creating non-user
     directories at root level
   - Changed from 500 Internal Server Error to proper 403 Forbidden

2. create_missing_parents flag not working (422 error):
   - Fixed SDK path handling - now sends full path instead of splitting into
     parent+basename
   - Added support for snake_case 'create_missing_parents' parameter in SDK
   - Made backend conditionally create or validate parents based on flag
   - Previously always called _get_existing_parent regardless of flag value

Changes:
- src/backend/src/api/APIError.js: Added 'cannot_create_in_root' error
- src/backend/src/filesystem/hl_operations/hl_mkdir.js: Added root validation
  and conditional parent creation logic
- src/puter-js/src/modules/FileSystem/operations/mkdir.js: Fixed path handling
  and parameter support
const is_user_dir = await first_component_node.isUserDirectory();

// Only block if it's NOT a user directory (user directories are allowed)
if ( is_user_dir !== true ) {
Copy link

Choose a reason for hiding this comment

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

nit:

Suggested change
if ( is_user_dir !== true ) {
if(is_user_dir){

actor: values.actor,
});
parent_node = values.create_missing_parents
? await this._create_parents({
Copy link

Choose a reason for hiding this comment

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

will values.create_missing_parents ever return a falsy value? if it will not, then logic below will never run

Copy link
Author

Choose a reason for hiding this comment

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

Yes, values.create_missing_parents can be falsy, and the _get_existing_parent branch will run in those cases. Here's why:

  1. FlagParam Default Behavior
    In FlagParam.js (line 26), when a flag is optional: true and no value is provided, it defaults to false:
    this.default = this.options.default ?? false;

  2. Router Handling
    In the mkdir.js router (lines 79-82), boolify() is used which can return false:

create_missing_parents: boolify(
    req.body.create_missing_ancestors ??
    req.body.create_missing_parents
)

If neither create_missing_ancestors nor create_missing_parents is provided in the request body, or if they're explicitly set to false, the value will be false.

  1. When the Branch Runs
    The _get_existing_parent branch will execute when:
  • create_missing_parents is not provided in the request (defaults to false)
  • create_missing_parents is explicitly set to false
  • The client doesn't pass the flag at all

The ternary at lines 317-324 is correct and both branches are reachable. The _get_existing_parent path is used when the caller expects all parent directories to already exist, which is a valid use case.

Copy link

@israx israx left a comment

Choose a reason for hiding this comment

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

good job so far

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.

2 participants